<commit_before>var inherits = require('util').inherits;
var Armed;

module.exports = function (HAPnode, config, functions) {
    var Accessory = HAPnode.Accessory;
    var Service = HAPnode.Service;
    var Characteristic = HAPnode.Characteristic;
    var uuid = HAPnode.uuid;
    var debug = HAPnode.debug;

    // Armed = function () {
    //     Characteristic.call(this, 'Armed', '00000067-0000-1000-8000-0026BB816241');
    //     this.setProps({
    //         format: Characteristic.Formats.BOOL,
    //         perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY]
    //     });
    //     this.value = this.getDefaultValue();
    // };
    // inherits(Armed, Characteristic);

    var module = {};

    module.newDevice = function (device) {

        var DeviceMap = [
          {
            name: 'MotionSensor',
            subcategory: 3,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                MotionDetected: {
                  getVariable: 'armedtripped',
                  type: 'boolean'
                },
                StatusActive: true,
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'ContactSensor',
            subcategory: 1,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                ContactSensorState: {
                  getVariable: 'tripped',
                  type: 'boolean'
                },
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'HumiditySensor',
            category: 16,
            subcategory: 0,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:HumiditySensor1',
            characteristics: {
                CurrentRelativeHumidity: {
                  getVariable: 'humidity'
                }
            }
          },
          {
            name: 'LightSensor',
            category: 18,
            subcategory: 0,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:LightSensor1',
            characteristics: {
                CurrentAmbientLightLevel: {
                  getVariable: 'light'
                }
            }
          },
          {
            name: 'CarbonMonoxideSensor',
            category: 4,
            subcategory: 5,
            battery: true,
            id: 'urn:schemas-micasaverde-com:device:SmokeSensor:1',
            characteristics: {
                CarbonMonoxideDetected: {
                  getVariable: 'armedtripped'
                }
            }
          },
          {
            name: 'SmokeSensor',
            category: 4,
            subcategory: 4,
            battery: true,
            id: 'urn:schemas-micasaverde-com:device:SmokeSensor:1',
            characteristics: {
                SmokeDetected: {
                  getVariable: 'armedtripped',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'ContactSensor',
            subcategory: 6,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                ContactSensorState: {
                  getVariable: 'armedtripped',
                  type: 'boolean'
                },
                StatusActive: {
                  getVariable: 'armed',
                  type: 'boolean'
                },
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          }
        ]

        var hapuuid = uuid.generate('device:sensor:' + config.cardinality + ':' + device.id),
            accessory = new Accessory(device.name, hapuuid),
            serviceMap = DeviceMap.find(function(service, index){
              console.log(service.name);
              return (service.category == device.category)&&(service.subcategory == device.subcategory);
            }),
            service = new Service[serviceMap.name](device.name);

        accessory.username = functions.genMac('device:' + config.cardinality + ':' + device.id);
        accessory.deviceid = device.id;

        Object.keys(serviceMap.characteristics).forEach(function(key){
          var map = serviceMap.characteristics[key],
          characteristic = Characteristic[key];
          // is characteristic read-write?
          if(map.setMethod){
            service.getCharacetristic(characteristic)
              .on('set', function(value, callback){
                var request = {
                  action: map.setMethod,
                  serviceId: service.id,
                  DeviceNum: device.id
                };
                request[setVariable] = value;
                functions
                  .executeAction(request)
                  .then(function(response){
                    debug("Armed set");
                    debug(response);
                    callback(response);
                  })
              });
          }
          service.getCharacteristic(Characteristic[key])
            .on('get', function(callback){
              var value = parseInt(functions.getVariable(device.id, map.getVariable));
              if(map.type == 'boolean'){
                value = Boolean(value);
              }
              callback(null, value);
            });

          // Update Loop, regular polling for updates.
          setInterval(function() {
            var value = parseInt(functions.getVariable(device.id, map.getVariable));
            if(map.type == 'boolean'){
              value = Boolean(value);
            }
            if (value !== service.getCharacteristic(characteristic)){
              service.setCharacteristic(characteristic,value);
            }
          }, 1000);
        });
        accessory.addService(service);

        accessory.on('identify', function (paired, callback) {
            debug("Identity of the sensor is %s", device.name);
            callback(); // success
          });

        if(serviceMap.battery){
          var batteryService = new Service.BatteryService(device.name);
          var batteryid = (device.parent>1)?device.parent:device.id;
          console.log('BATTERY ID:', batteryid);
          batteryService
              .getCharacteristic(Characteristic.BatteryLevel)
              .on('get', function (callback) {
                  debug('Getting battery level for', device.name);
                  callback(null, parseInt(functions.getVariable(batteryid, 'batterylevel')));
              });
          batteryService
              .getCharacteristic(Characteristic.StatusLowBattery)
              .on('get', function (callback) {
                  callback(null, functions.getVariable(batteryid, 'batterylevel') < 20);
              });
          accessory.addService(batteryService);
        }

        return accessory;
    };

    return module;
};
<commit_msg>fixing motion sensor, as tripped is fairly reliable on that type<commit_after>var inherits = require('util').inherits;
var Armed;

module.exports = function (HAPnode, config, functions) {
    var Accessory = HAPnode.Accessory;
    var Service = HAPnode.Service;
    var Characteristic = HAPnode.Characteristic;
    var uuid = HAPnode.uuid;
    var debug = HAPnode.debug;

    // Armed = function () {
    //     Characteristic.call(this, 'Armed', '00000067-0000-1000-8000-0026BB816241');
    //     this.setProps({
    //         format: Characteristic.Formats.BOOL,
    //         perms: [Characteristic.Perms.READ, Characteristic.Perms.WRITE, Characteristic.Perms.NOTIFY]
    //     });
    //     this.value = this.getDefaultValue();
    // };
    // inherits(Armed, Characteristic);

    var module = {};

    module.newDevice = function (device) {

        var DeviceMap = [
          {
            name: 'MotionSensor',
            subcategory: 3,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                MotionDetected: {
                  getVariable: 'tripped',
                  type: 'boolean'
                },
                StatusActive: true,
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'ContactSensor',
            subcategory: 1,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                ContactSensorState: {
                  getVariable: 'tripped',
                  type: 'boolean'
                },
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'HumiditySensor',
            category: 16,
            subcategory: 0,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:HumiditySensor1',
            characteristics: {
                CurrentRelativeHumidity: {
                  getVariable: 'humidity'
                }
            }
          },
          {
            name: 'LightSensor',
            category: 18,
            subcategory: 0,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:LightSensor1',
            characteristics: {
                CurrentAmbientLightLevel: {
                  getVariable: 'light'
                }
            }
          },
          {
            name: 'CarbonMonoxideSensor',
            category: 4,
            subcategory: 5,
            battery: true,
            id: 'urn:schemas-micasaverde-com:device:SmokeSensor:1',
            characteristics: {
                CarbonMonoxideDetected: {
                  getVariable: 'armedtripped'
                }
            }
          },
          {
            name: 'SmokeSensor',
            category: 4,
            subcategory: 4,
            battery: true,
            id: 'urn:schemas-micasaverde-com:device:SmokeSensor:1',
            characteristics: {
                SmokeDetected: {
                  getVariable: 'armedtripped',
                  type: 'boolean'
                }
            }
          },
          {
            name: 'ContactSensor',
            subcategory: 6,
            category: 4,
            battery: true,
            id: 'urn:micasaverde-com:serviceId:SecuritySensor1',
            characteristics: {
                ContactSensorState: {
                  getVariable: 'armedtripped',
                  type: 'boolean'
                },
                StatusActive: {
                  getVariable: 'armed',
                  type: 'boolean'
                },
                StatusFault: {
                  getVariable: 'commFailure',
                  type: 'boolean'
                }
            }
          }
        ]

        var hapuuid = uuid.generate('device:sensor:' + config.cardinality + ':' + device.id),
            accessory = new Accessory(device.name, hapuuid),
            serviceMap = DeviceMap.find(function(service, index){
              console.log(service.name);
              return (service.category == device.category)&&(service.subcategory == device.subcategory);
            }),
            service = new Service[serviceMap.name](device.name);

        accessory.username = functions.genMac('device:' + config.cardinality + ':' + device.id);
        accessory.deviceid = device.id;

        Object.keys(serviceMap.characteristics).forEach(function(key){
          var map = serviceMap.characteristics[key],
          characteristic = Characteristic[key];
          // is characteristic read-write?
          if(map.setMethod){
            service.getCharacetristic(characteristic)
              .on('set', function(value, callback){
                var request = {
                  action: map.setMethod,
                  serviceId: service.id,
                  DeviceNum: device.id
                };
                request[setVariable] = value;
                functions
                  .executeAction(request)
                  .then(function(response){
                    debug("Armed set");
                    debug(response);
                    callback(response);
                  })
              });
          }
          service.getCharacteristic(Characteristic[key])
            .on('get', function(callback){
              var value = parseInt(functions.getVariable(device.id, map.getVariable));
              if(map.type == 'boolean'){
                value = Boolean(value);
              }
              callback(null, value);
            });

          // Update Loop, regular polling for updates.
          setInterval(function() {
            var value = parseInt(functions.getVariable(device.id, map.getVariable));
            if(map.type == 'boolean'){
              value = Boolean(value);
            }
            if (value !== service.getCharacteristic(characteristic)){
              service.setCharacteristic(characteristic,value);
            }
          }, 1000);
        });
        accessory.addService(service);

        accessory.on('identify', function (paired, callback) {
            debug("Identity of the sensor is %s", device.name);
            callback(); // success
          });

        if(serviceMap.battery){
          var batteryService = new Service.BatteryService(device.name);
          var batteryid = (device.parent>1)?device.parent:device.id;
          console.log('BATTERY ID:', batteryid);
          batteryService
              .getCharacteristic(Characteristic.BatteryLevel)
              .on('get', function (callback) {
                  debug('Getting battery level for', device.name);
                  callback(null, parseInt(functions.getVariable(batteryid, 'batterylevel')));
              });
          batteryService
              .getCharacteristic(Characteristic.StatusLowBattery)
              .on('get', function (callback) {
                  callback(null, functions.getVariable(batteryid, 'batterylevel') < 20);
              });
          accessory.addService(batteryService);
        }

        return accessory;
    };

    return module;
};
<|endoftext|>


<commit_before>/* ugrid client side library.  */
'use strict';

var net = require('net');
var thunkify = require('thunkify');
var ugridMsg = require('./ugrid-msg.js');
var websocket = require('websocket-stream');	// Keep this order to avoid browserify problems!!

module.exports = UgridClient;

function UgridClient(arg) {
	if (!(this instanceof UgridClient))
		return new UgridClient(arg);
	var host = (arg && arg.host) || process.env.UGRID_HOST || 'localhost';
	var port = (arg && arg.port) || process.env.UGRID_PORT || 12346;
	var events = {};
	var hostId = {};
	var subscriptions = [];
	var sock;
	var recovering = false;
	var lastUuid, lastSent;
	var pending = {};
	var cid = 0;
	var cidMax = 10000000;
	var myId, myUuid, suid;
	var disconnect = false;
	var secondary;
	var hosts, nhosts;

	function connect_cb(callback) {
		sock = net.connect(port, host, function () {
			handleConnect(callback);
		});
		sock.on('end', events.end);
		sock.on('error', events.error);
	}

	function wsConnect_cb(callback) {
		sock = websocket('ws://' + host + ':' + port);
		handleConnect(callback);
		sock.on('end', events.end);
		sock.on('error', events.error);
	}

	function handleConnect(callback) {
		var decoder = ugridMsg.Decoder();
		sock.pipe(decoder);

		var msg = {cmd: 'connect', data: arg.data};
		if (myUuid)
			msg.uuid = myUuid;
		send_cb(0, msg, function (err, res) {
			myId = res.id;
			myUuid = res.uuid;
			suid = myUuid.substr(0, 8);
			if (subscriptions.length > 0) {
				var publishers = [];
				for (var v in subscriptions)
					publishers.push({uuid: subscriptions[v]});
				setTimeout(function () {subscribe(publishers)}, 0);
			}
			callback(err, res);
		});
		decoder.on('Message', function (to, len, data) {
			var o = JSON.parse(data.slice(8));
			// console.log(suid + ' ' + myId + ' <---- ' + (o.from||0) + ' ' + (o.cid||0) + ' ' + o.cmd);
			if (o.ufrom && ! hostId[o.ufrom])
				hostId[o.ufrom] = o.from;
			if (o.cmd in events)
				events[o.cmd](o);
		});
	}

	function getId(uuid, nTry, o, callback) {
		send_cb(0, {cmd: 'id', data: uuid}, function (err, res) {
			if (res) {
				o.id = hostId[uuid] = res;
				o.from = myId;
				if (!o.cid) {
					o.cid = (cid == cidMax ? 0 : cid++);
					if (callback)
						pending[o.cid] = callback;
				}
				if (!recovering) {
					lastUuid = uuid;
					lastSent = JSON.stringify(o);
				}
				sock.write(ugridMsg.encode(o));
				// console.log(suid + ' ' + myId + ' 1----> ' + (o.id || 0) + ' ' + o.cid + ': ' + o.cmd);
			} else {
				if (--nTry < 0) {
					if (pending[o.cid]) {
						console.error("getId failed");
						pending[o.cid]("getId failed");
						delete(pending[o.cid]);
					}
				} else {
					// console.log('reply id ' + uuid + ': no res, try again');
					setTimeout(function () {
						getId(uuid, nTry, o, callback);
					}, Math.floor(Math.random() * 2000));
				}
			}
		});
	}

	function send_cb(uuid, o, callback) {
		if (uuid) {
			if (hostId[uuid])
				o.id = hostId[uuid];
			else
				return getId(uuid, 3, o, callback);
		}
		if (!o.cid) {
			o.cid = (cid == cidMax ? 0 : cid++);
			if (callback)
				pending[o.cid] = callback;
		}
		o.from = myId;
		if (!recovering) {
			lastUuid = uuid;
			lastSent = JSON.stringify(o);
		}
		sock.write(ugridMsg.encode(o));
		// console.log(suid + ' ' + myId + ' 0----> ' + (o.id || 0) + ' ' + o.cid + ': ' + o.cmd);
	}

	function subscribe(publishers) {
		var v;
		for (v in publishers) {
			if (subscriptions.indexOf(publishers[v].uuid) < 0)
				subscriptions.push(publishers[v].uuid);
		}
		send_cb(0, {cmd: 'subscribe', data: publishers});
	}

	function handleDisconnect(error) {
		if (disconnect) return;
		console.error(suid + '(' + myId + ') Unexpected connection close ' + (error || ""));
		if (!secondary.host) process.exit(1);
		hostId = {};
		host = secondary.host;
		port = secondary.port;
		recovering = true;
		connect_cb(function () {
			console.log(suid + '(' + myId + ') reconnected to ' + host + ':' + port);
			if (lastSent)
				send_cb(lastUuid, JSON.parse(lastSent));
			recovering = false;
		});
	}

	events.reply = function (o) {
		if (!pending[o.cid]) return;
		pending[o.cid](o.error, o.data);
		delete(pending[o.cid]);
	};

	events.end = events.error = handleDisconnect;

	events.secondary = function (o) {
		secondary = o.data;
	};

	this.connect_cb = connect_cb;
	this.wsConnect_cb = wsConnect_cb;

	this.on = function (event, callback) {
		if (event === 'end' || event === 'error') {
			sock.removeListener('end', events[event]);
			sock.on(event, callback);
		}
		events[event] = callback;
	};

	this.disconnect = function () {
		disconnect = true;
		sock.end();
	};

	this.send_cb = send_cb;

	this.send = function (o) {send_cb(o);};

	this.devices_cb = function (o, callback) {
		send_cb(0, {cmd: 'devices', data: o, id: 0}, function (err, res) {
			for (var i in res)
				hostId[res[i].uuid] = res[i].id;
			callback(err, res);
		});
	};

	this.publish = function (data) {
		send_cb(0, {cmd: 'publish', data: data, id: 2});
	};

	this.request_cb = function (dest, data, callback) {
		send_cb(dest.uuid, {cmd: 'request', ufrom: myUuid, data: data}, callback);
	};

	this.reply = function (msg, error, data) {
		var uuid = msg.ufrom;
		msg.cmd = 'reply';
		msg.id = msg.from;
		msg.ufrom = undefined;
		msg.data = data;
		msg.error = error;
		send_cb(uuid, msg);
	};

	this.subscribe = subscribe;

	this.unsubscribe = function unsubscribe(publishers) {
		var i, v;
		for (v in publishers) {
			if ((i = subscriptions.indexOf(publishers[v].uuid)) >= 0)
				subscriptions.splice(i, 1);
		}
		send_cb(0, {cmd: 'unsubscribe', data: publishers});
	};

	this.connect = thunkify(this.connect_cb);
	this.devices = thunkify(this.devices_cb);
	this.request = thunkify(this.request_cb);
	this.wsConnect = thunkify(this.wsConnect_cb);
}
<commit_msg>Add UGRID_DEBUG env. var. to control debug traces, fixes #40<commit_after>/* ugrid client side library.  */
'use strict';

var net = require('net');
var thunkify = require('thunkify');
var ugridMsg = require('./ugrid-msg.js');
var websocket = require('websocket-stream');	// Keep this order to avoid browserify problems!!

module.exports = UgridClient;

function UgridClient(arg) {
	if (!(this instanceof UgridClient))
		return new UgridClient(arg);
	var host = (arg && arg.host) || process.env.UGRID_HOST || 'localhost';
	var port = (arg && arg.port) || process.env.UGRID_PORT || 12346;
	var debug = (arg && arg.debug) || process.env.UGRID_DEBUG;
	var events = {};
	var hostId = {};
	var subscriptions = [];
	var sock;
	var recovering = false;
	var lastUuid, lastSent;
	var pending = {};
	var cid = 0;
	var cidMax = 10000000;
	var myId, myUuid, suid;
	var disconnect = false;
	var secondary;
	var hosts, nhosts;

	function connect_cb(callback) {
		sock = net.connect(port, host, function () {
			handleConnect(callback);
		});
		sock.on('end', events.end);
		sock.on('error', events.error);
	}

	function wsConnect_cb(callback) {
		sock = websocket('ws://' + host + ':' + port);
		handleConnect(callback);
		sock.on('end', events.end);
		sock.on('error', events.error);
	}

	function handleConnect(callback) {
		var decoder = ugridMsg.Decoder();
		sock.pipe(decoder);

		var msg = {cmd: 'connect', data: arg.data};
		if (myUuid)
			msg.uuid = myUuid;
		send_cb(0, msg, function (err, res) {
			myId = res.id;
			myUuid = res.uuid;
			suid = myUuid.substr(0, 8);
			if (subscriptions.length > 0) {
				var publishers = [];
				for (var v in subscriptions)
					publishers.push({uuid: subscriptions[v]});
				setTimeout(function () {subscribe(publishers)}, 0);
			}
			callback(err, res);
		});
		decoder.on('Message', function (to, len, data) {
			var o = JSON.parse(data.slice(8));
			debug && console.error(suid + ' ' + myId + ' <---- ' + (o.from||0) + ' ' + (o.cid||0) + ' ' + o.cmd);
			if (o.ufrom && ! hostId[o.ufrom])
				hostId[o.ufrom] = o.from;
			if (o.cmd in events)
				events[o.cmd](o);
		});
	}

	function getId(uuid, nTry, o, callback) {
		send_cb(0, {cmd: 'id', data: uuid}, function (err, res) {
			if (res) {
				o.id = hostId[uuid] = res;
				o.from = myId;
				if (!o.cid) {
					o.cid = (cid == cidMax ? 0 : cid++);
					if (callback)
						pending[o.cid] = callback;
				}
				if (!recovering) {
					lastUuid = uuid;
					lastSent = JSON.stringify(o);
				}
				sock.write(ugridMsg.encode(o));
				debug && console.error(suid + ' ' + myId + ' 1----> ' + (o.id || 0) + ' ' + o.cid + ': ' + o.cmd);
			} else {
				if (--nTry < 0) {
					if (pending[o.cid]) {
						console.error("getId failed");
						pending[o.cid]("getId failed");
						delete(pending[o.cid]);
					}
				} else {
					setTimeout(function () {
						getId(uuid, nTry, o, callback);
					}, Math.floor(Math.random() * 2000));
				}
			}
		});
	}

	function send_cb(uuid, o, callback) {
		if (uuid) {
			if (hostId[uuid])
				o.id = hostId[uuid];
			else
				return getId(uuid, 3, o, callback);
		}
		if (!o.cid) {
			o.cid = (cid == cidMax ? 0 : cid++);
			if (callback)
				pending[o.cid] = callback;
		}
		o.from = myId;
		if (!recovering) {
			lastUuid = uuid;
			lastSent = JSON.stringify(o);
		}
		sock.write(ugridMsg.encode(o));
		debug && console.error(suid + ' ' + myId + ' 0----> ' + (o.id || 0) + ' ' + o.cid + ': ' + o.cmd);
	}

	function subscribe(publishers) {
		var v;
		for (v in publishers) {
			if (subscriptions.indexOf(publishers[v].uuid) < 0)
				subscriptions.push(publishers[v].uuid);
		}
		send_cb(0, {cmd: 'subscribe', data: publishers});
	}

	function handleDisconnect(error) {
		if (disconnect) return;
		console.error(suid + ' ' + myId + ' Unexpected connection close ' + (error || ""));
		if (!secondary.host) process.exit(1);
		hostId = {};
		host = secondary.host;
		port = secondary.port;
		recovering = true;
		connect_cb(function () {
			console.error(suid + ' ' + myId + ' reconnected to ' + host + ':' + port);
			if (lastSent)
				send_cb(lastUuid, JSON.parse(lastSent));
			recovering = false;
		});
	}

	events.reply = function (o) {
		if (!pending[o.cid]) return;
		pending[o.cid](o.error, o.data);
		delete(pending[o.cid]);
	};

	events.end = events.error = handleDisconnect;

	events.secondary = function (o) {
		secondary = o.data;
	};

	this.connect_cb = connect_cb;
	this.wsConnect_cb = wsConnect_cb;

	this.on = function (event, callback) {
		if (event === 'end' || event === 'error') {
			sock.removeListener('end', events[event]);
			sock.on(event, callback);
		}
		events[event] = callback;
	};

	this.disconnect = function () {
		disconnect = true;
		sock.end();
	};

	this.send_cb = send_cb;

	this.send = function (o) {send_cb(o);};

	this.devices_cb = function (o, callback) {
		send_cb(0, {cmd: 'devices', data: o, id: 0}, function (err, res) {
			for (var i in res)
				hostId[res[i].uuid] = res[i].id;
			callback(err, res);
		});
	};

	this.publish = function (data) {
		send_cb(0, {cmd: 'publish', data: data, id: 2});
	};

	this.request_cb = function (dest, data, callback) {
		send_cb(dest.uuid, {cmd: 'request', ufrom: myUuid, data: data}, callback);
	};

	this.reply = function (msg, error, data) {
		var uuid = msg.ufrom;
		msg.cmd = 'reply';
		msg.id = msg.from;
		msg.ufrom = undefined;
		msg.data = data;
		msg.error = error;
		send_cb(uuid, msg);
	};

	this.subscribe = subscribe;

	this.unsubscribe = function unsubscribe(publishers) {
		var i, v;
		for (v in publishers) {
			if ((i = subscriptions.indexOf(publishers[v].uuid)) >= 0)
				subscriptions.splice(i, 1);
		}
		send_cb(0, {cmd: 'unsubscribe', data: publishers});
	};

	this.connect = thunkify(this.connect_cb);
	this.devices = thunkify(this.devices_cb);
	this.request = thunkify(this.request_cb);
	this.wsConnect = thunkify(this.wsConnect_cb);
}
<|endoftext|>


<commit_before>// Ugrid

var net = require('net');
var byline = require('byline');
var thunkify = require('thunkify');

module.exports = function(arg) {
	var host = arg.host;
	var port = arg.port;
	var data = arg.data ? arg.data : {};
	var my_uuid, grid, my_token;
	var pending_cmd = {};
	var grid_events = {};
	var cmd_cnt = 0;

	function send_cmd(json) {
		var cmd = {
			cmd: json.cmd,
			from: my_uuid ? my_uuid : null,
			token: my_token ? my_token : null,
			cmd_id: json.cmd_id ? json.cmd_id : get_next_cmd_id(),
			data: json.data
		}
		if (json.process)
			pending_cmd[cmd.cmd_id] = {process: json.process};
		grid.write(JSON.stringify(cmd) + '\n');
	}

	this.connect_cb = function(callback) {
		grid = net.connect(port, host, function() {
			send('connect', data, function(err, res) {
				if (res) {
					my_uuid = res.uuid;
					my_token = res.token;
				}
				callback(err, res);
			});
			byline(grid).on('data', function(d) {
				try {
					var o = JSON.parse(d, function(key, value) {
						if (value === "gridNaN")
							return NaN;
						return value;
					});
					if (o.data && o.data.err)
						throw o.data.err;
					if (o.cmd in grid_events) {	      // command from server
						grid_events[o.cmd](o);
					} else if (o.cmd_id in pending_cmd) { // answer to previous cmd
						pending_cmd[o.cmd_id].process(o.data.err, o.data.result);
					}
				} catch (error) {
					console.trace('on received line:\n' + d + '\nError: ' + error);
					process.exit(1);
				}
			});
		});
	};

	this.on = function(event, callback) {
		grid_events[event] = callback;
	};

	this.disconnect = function() {
		grid.end();
	};

	var send = this.send_cb = function(cmd, data, callback) {
		var o = {cmd: cmd, data: data};
		if (o.cmd === 'answer') {
			o.cmd_id = o.data.cmd_id;
		}
		if (callback) {
			o.process = function(error, result, cmd_id) {
				callback(error, result);
			};
		}
		send_cmd(o);
	};

	var get_next_cmd_id = this.get_next_cmd_id = function () {
		if (cmd_cnt++ == 1000000)
			cmd_cnt = 0;
		return cmd_cnt;
	};

	this.connect = thunkify(this.connect_cb);
	this.send = thunkify(this.send_cb);
};
<commit_msg>fix memory leak in ugrid-client lib<commit_after>// Ugrid

var assert = require('assert');
var net = require('net');
var byline = require('byline');
var thunkify = require('thunkify');

module.exports = function(arg) {
	var host = arg.host;
	var port = arg.port;
	var data = arg.data ? arg.data : {};
	var my_uuid, grid, my_token;
	var pending_cmd = {};
	var grid_events = {};
	var cmd_cnt = 0;

	function send_cmd(json) {
		var cmd = {
			cmd: json.cmd,
			from: my_uuid ? my_uuid : null,
			token: my_token ? my_token : null,
			cmd_id: json.cmd_id ? json.cmd_id : get_next_cmd_id(),
			data: json.data
		}
		if (json.process)
			pending_cmd[cmd.cmd_id] = {process: json.process};
		grid.write(JSON.stringify(cmd) + '\n');
	}

	this.connect_cb = function(callback) {
		grid = net.connect(port, host, function() {
			send('connect', data, function(err, res) {
				if (res) {
					my_uuid = res.uuid;
					my_token = res.token;
				}
				callback(err, res);
			});
			byline(grid).on('data', function(d) {
				try {
					var o = JSON.parse(d, function(key, value) {
						if (value === "gridNaN")
							return NaN;
						return value;
					});
					if (o.data && o.data.err)
						throw o.data.err;
					if (o.cmd in grid_events) {	      // command from server
						grid_events[o.cmd](o);
					} else if (o.cmd_id in pending_cmd) { // answer to previous cmd
						assert(o.data);
						pending_cmd[o.cmd_id].process(o.data.err, o.data.result);
						delete(pending_cmd[o.cmd_id]);
					}
				} catch (error) {
					console.trace('on received line:\n' + d + '\nError: ' + error);
					process.exit(1);
				}
			});
		});
	};

	this.on = function(event, callback) {
		grid_events[event] = callback;
	};

	this.disconnect = function() {
		grid.end();
	};

	var send = this.send_cb = function(cmd, data, callback) {
		var o = {cmd: cmd, data: data};
		if (o.cmd === 'answer') {
			o.cmd_id = o.data.cmd_id;
		}
		if (callback) {
			o.process = function(error, result, cmd_id) {
				callback(error, result);
			};
		}
		send_cmd(o);
	};

	var get_next_cmd_id = this.get_next_cmd_id = function () {
		if (cmd_cnt++ == 1000000) {
			console.log("cmd_id overflow!");
			cmd_cnt = 0;
		}
		return cmd_cnt;
	};

	this.connect = thunkify(this.connect_cb);
	this.send = thunkify(this.send_cb);
};
<|endoftext|>


<commit_before>'use strict'
module.exports = function (href, hash) {
  var safeUrl = (href || '').split('?')[0]
  safeUrl = safeUrl.replace(/^https?:\/\//i, '')

  // Account for relative paths
  if (safeUrl[0] === '/') {
    safeUrl = (window.location.host || '') + safeUrl
  }

  // Trim trailing slash
  if (safeUrl[safeUrl.length - 1] === '/') safeUrl = safeUrl.slice(0, safeUrl.length - 1)

  // Append hash paths
  if ((hash || '').match(/\?/)) {
    hash = hash.split('?')[0].slice(1)
    if (hash[0] !== '/') safeUrl += '/'
    safeUrl += hash
  }

  // Replace IDs
  var urlParts = safeUrl.split(/[/.]/g)
  for (var i = 0; i < urlParts.length; i++) {
    if (urlParts[i].match(/^[A-Z0-9-]+$/)) safeUrl = safeUrl.replace(urlParts[i], 'CODE')
  }

  // Strip any quotes
  safeUrl = safeUrl.replace(/["']/gi, '')

  var path = safeUrl.split('/')
  var host = path.shift()
  path = path.join('/')
  return [ host, path ]
}
<commit_msg>We no longer have a mix of URL configuration - let's remove the check for a second query string start as its likely we won't always have it<commit_after>'use strict'
module.exports = function (href, hash = '') {
  var safeUrl = (href || '').split('?')[0]
  safeUrl = safeUrl.replace(/^https?:\/\//i, '')

  // Account for relative paths
  if (safeUrl[0] === '/') {
    safeUrl = (window.location.host || '') + safeUrl
  }

  // Trim trailing slash
  if (safeUrl[safeUrl.length - 1] === '/') safeUrl = safeUrl.slice(0, safeUrl.length - 1)

  // Append hash paths
  hash = hash.split('?')[0].slice(1)
  if (hash[0] !== '/') safeUrl += '/'
  safeUrl += hash

  // Replace IDs
  var urlParts = safeUrl.split(/[/.]/g)
  for (var i = 0; i < urlParts.length; i++) {
    if (urlParts[i].length > 25 ) safeUrl = safeUrl.replace(urlParts[i], 'UUID')
    if (urlParts[i].match(/^[A-Z0-9-]+$/)) safeUrl = safeUrl.replace(urlParts[i], 'CODE')
  }

  // Strip any quotes
  safeUrl = safeUrl.replace(/["']/gi, '')

  var path = safeUrl.split('/')
  var host = path.shift()
  path = path.join('/')
  return [ host, path ]
}
<|endoftext|>


<commit_before>var extend = require('./extend')

function slice (x) {
  return Array.prototype.slice.call(x)
}

function join (x) {
  return slice(x).join('')
}

module.exports = function createEnvironment () {
  // Unique variable id counter
  var varCounter = 0

  // Linked values are passed from this scope into the generated code block
  // Calling link() passes a value into the generated scope and returns
  // the variable name which it is bound to
  var linkedNames = []
  var linkedValues = []
  function link (value) {
    for (var i = 0; i < linkedValues.length; ++i) {
      if (linkedValues[i] === value) {
        return linkedNames[i]
      }
    }

    var name = 'g' + (varCounter++)
    linkedNames.push(name)
    linkedValues.push(value)
    return name
  }

  // create a code block
  function block () {
    var code = []
    function push () {
      code.push.apply(code, slice(arguments))
    }

    var vars = []
    function def () {
      var name = 'v' + (varCounter++)
      vars.push(name)

      if (arguments.length > 0) {
        code.push(name, '=')
        code.push.apply(code, slice(arguments))
        code.push(';')
      }

      return name
    }

    return extend(push, {
      def: def,
      toString: function () {
        return join([
          (vars.length > 0 ? 'var ' + vars + ';' : ''),
          join(code)
        ])
      }
    })
  }

  function scope () {
    var entry = block()
    var exit = block()

    var entryToString = entry.toString
    var exitToString = exit.toString

    function save (object, prop) {
      exit(object, prop, '=', entry.def(object, prop), ';')
    }

    return extend(entry, {
      entry: entry,
      exit: exit,
      save: save,
      set: function (object, prop, value) {
        save(object, prop)
        entry(object, prop, '=', value, ';')
      },
      toString: function () {
        return entryToString() + exitToString()
      }
    })
  }

  function conditional () {
    var pred = join(arguments)
    var thenBlock = scope()
    var elseBlock = scope()

    var thenToString = thenBlock.toString
    var elseToString = elseBlock.toString

    return extend(thenBlock, {
      then: function () {
        thenBlock.apply(thenBlock, slice(arguments))
        return this
      },
      else: function () {
        elseBlock.apply(elseBlock, slice(arguments))
        return this
      },
      toString: function () {
        var elseClause = elseToString()
        if (elseClause) {
          elseClause = 'else{' + elseClause + '}'
        }
        return join([
          'if(', pred, '){',
          thenToString(),
          '}', elseClause
        ])
      }
    })
  }

  // procedure list
  var globalBlock = block()
  var procedures = {}
  function proc (name, count) {
    var args = []
    function arg () {
      var name = 'a' + args.length
      args.push(name)
      return name
    }

    count = count || 0
    for (var i = 0; i < count; ++i) {
      arg()
    }

    var body = scope()
    var bodyToString = body.toString

    var result = procedures[name] = extend(body, {
      arg: arg,
      toString: function () {
        return join([
          'function(', args.join(), '){',
          bodyToString(),
          '}'
        ])
      }
    })

    return result
  }

  function compile () {
    var code = ['"use strict";',
      globalBlock,
      'return {']
    Object.keys(procedures).forEach(function (name) {
      code.push('"', name, '":', procedures[name].toString(), ',')
    })
    code.push('}')
    var src = join(code)
      .replace(/;/g, ';\n')
      .replace(/}/g, '}\n')
      .replace(/{/g, '{\n')
    var proc = Function.apply(null, linkedNames.concat(src))
//    console.log('src: ', src)
    return proc.apply(null, linkedValues)
  }

  return {
    global: globalBlock,
    link: link,
    block: block,
    proc: proc,
    scope: scope,
    cond: conditional,
    compile: compile
  }
}
<commit_msg>fix code generation bug.  accidentally overloading entry toString for blocks<commit_after>var extend = require('./extend')

function slice (x) {
  return Array.prototype.slice.call(x)
}

function join (x) {
  return slice(x).join('')
}

module.exports = function createEnvironment () {
  // Unique variable id counter
  var varCounter = 0

  // Linked values are passed from this scope into the generated code block
  // Calling link() passes a value into the generated scope and returns
  // the variable name which it is bound to
  var linkedNames = []
  var linkedValues = []
  function link (value) {
    for (var i = 0; i < linkedValues.length; ++i) {
      if (linkedValues[i] === value) {
        return linkedNames[i]
      }
    }

    var name = 'g' + (varCounter++)
    linkedNames.push(name)
    linkedValues.push(value)
    return name
  }

  // create a code block
  function block () {
    var code = []
    function push () {
      code.push.apply(code, slice(arguments))
    }

    var vars = []
    function def () {
      var name = 'v' + (varCounter++)
      vars.push(name)

      if (arguments.length > 0) {
        code.push(name, '=')
        code.push.apply(code, slice(arguments))
        code.push(';')
      }

      return name
    }

    return extend(push, {
      def: def,
      toString: function () {
        return join([
          (vars.length > 0 ? 'var ' + vars + ';' : ''),
          join(code)
        ])
      }
    })
  }

  function scope () {
    var entry = block()
    var exit = block()

    var entryToString = entry.toString
    var exitToString = exit.toString

    function save (object, prop) {
      exit(object, prop, '=', entry.def(object, prop), ';')
    }

    return extend(function () {
      entry.apply(entry, slice(arguments))
    }, {
      def: entry.def,
      entry: entry,
      exit: exit,
      save: save,
      set: function (object, prop, value) {
        save(object, prop)
        entry(object, prop, '=', value, ';')
      },
      toString: function () {
        return entryToString() + exitToString()
      }
    })
  }

  function conditional () {
    var pred = join(arguments)
    var thenBlock = scope()
    var elseBlock = scope()

    var thenToString = thenBlock.toString
    var elseToString = elseBlock.toString

    return extend(thenBlock, {
      then: function () {
        thenBlock.apply(thenBlock, slice(arguments))
        return this
      },
      else: function () {
        elseBlock.apply(elseBlock, slice(arguments))
        return this
      },
      toString: function () {
        var elseClause = elseToString()
        if (elseClause) {
          elseClause = 'else{' + elseClause + '}'
        }
        return join([
          'if(', pred, '){',
          thenToString(),
          '}', elseClause
        ])
      }
    })
  }

  // procedure list
  var globalBlock = block()
  var procedures = {}
  function proc (name, count) {
    var args = []
    function arg () {
      var name = 'a' + args.length
      args.push(name)
      return name
    }

    count = count || 0
    for (var i = 0; i < count; ++i) {
      arg()
    }

    var body = scope()
    var bodyToString = body.toString

    var result = procedures[name] = extend(body, {
      arg: arg,
      toString: function () {
        return join([
          'function(', args.join(), '){',
          bodyToString(),
          '}'
        ])
      }
    })

    return result
  }

  function compile () {
    var code = ['"use strict";',
      globalBlock,
      'return {']
    Object.keys(procedures).forEach(function (name) {
      code.push('"', name, '":', procedures[name].toString(), ',')
    })
    code.push('}')
    var src = join(code)
      .replace(/;/g, ';\n')
      .replace(/}/g, '}\n')
      .replace(/{/g, '{\n')
    var proc = Function.apply(null, linkedNames.concat(src))
    // console.log('src: ', src)
    return proc.apply(null, linkedValues)
  }

  return {
    global: globalBlock,
    link: link,
    block: block,
    proc: proc,
    scope: scope,
    cond: conditional,
    compile: compile
  }
}
<|endoftext|>


<commit_before>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Provides the current version of cast.
 *
 * These are written in an easily parsable format for use by
 * other (non-js) scripts to easily grep out the version number.
 */

var CAST_VERSION_MAJOR = 0;
var CAST_VERSION_MINOR = 1;
var CAST_VERSION_PATCH = 2;

/* change this on release tags */
var CAST_IS_DEV = true;

/** Major version */
exports.MAJOR = CAST_VERSION_MAJOR;
/** Minor version */
exports.MINOR = CAST_VERSION_MINOR;
/** Patch level */
exports.PATCH = CAST_VERSION_PATCH;
/** Boolean testing if this is a development version or release version */
exports.IS_DEV = CAST_IS_DEV;

/**
 * Get the current version of Cast.
 * @return {String} Dot'ed format string of the version.
 */
exports.toString = function() {
  var dstr = '-dev';

  if (exports.IS_DEV === false) {
    dstr = '-release';
  }

  return 'cast-' + CAST_VERSION_MAJOR + '.' + CAST_VERSION_MINOR + '.' + CAST_VERSION_PATCH + '' + dstr;
};
<commit_msg>Bump verion number.<commit_after>/*
 * Licensed to Cloudkick, Inc ('Cloudkick') under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * Cloudkick licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * Provides the current version of cast.
 *
 * These are written in an easily parsable format for use by
 * other (non-js) scripts to easily grep out the version number.
 */

var CAST_VERSION_MAJOR = 0;
var CAST_VERSION_MINOR = 2;
var CAST_VERSION_PATCH = 0;

/* change this on release tags */
var CAST_IS_DEV = false;

/** Major version */
exports.MAJOR = CAST_VERSION_MAJOR;
/** Minor version */
exports.MINOR = CAST_VERSION_MINOR;
/** Patch level */
exports.PATCH = CAST_VERSION_PATCH;
/** Boolean testing if this is a development version or release version */
exports.IS_DEV = CAST_IS_DEV;

/**
 * Get the current version of Cast.
 * @return {String} Dot'ed format string of the version.
 */
exports.toString = function() {
  var dstr = '-dev';

  if (exports.IS_DEV === false) {
    dstr = '-release';
  }

  return 'cast-' + CAST_VERSION_MAJOR + '.' + CAST_VERSION_MINOR + '.' + CAST_VERSION_PATCH + '' + dstr;
};
<|endoftext|>


<commit_before>'use strict';
var insertAnalyzers = require('./analytics').insertAnalyzers;
var workerCount = require('os').cpus().length;
var processDone = 0;
var moment = require('moment');

var _context;

var argv = require('yargs')
    .argv;

function getJob() {
    var jobFile;

    jobFile = process.cwd() + '/job.json';

    if (argv.job) {
        jobFile = argv.job;
    }

    return require(jobFile);
}

function initializeJob(context) {
    _context = context;

    var job = getJob();

    var scheduler = lifecycle(job);

    var jobQueue = job.process.slice();
    var readerConfig = jobQueue.shift();
    var senderConfig = jobQueue.pop();

    var reader = require('../readers/' + readerConfig.op);
    var sender = require('../senders/' + senderConfig.op);
    var processors = jobQueue.map(function(job) {
        return require('../processors/' + job.op)
    });

    var queue = [];
    queue.push(reader.newReader(context, readerConfig));

    //using mutated jobQueue to provide opConfig
    processors.forEach(function(job, i) {
        queue.push(job.newProcessor(context, jobQueue[i]))
    });
    queue.push(sender.newSender(context, senderConfig));

    if (job.analytics) {
        queue = insertAnalyzers(queue);
    }

    return {
        analytics: job.analytics,
        reader: reader,
        sender: sender,
        processors: processors,
        jobs: job.process,
        queue: queue,
        readerConfig: readerConfig,
        scheduler: scheduler

    };
}

function sendMessage(id, message) {
    _context.cluster.workers[id].send(message);
}

function lifecycle(job) {
    if (job.lifecycle === 'once') {
        return once;
    }
    if (job.lifecycle === 'periodic') {
        return periodic;
    }
    if (job.lifecycle === 'persistent') {
        return persistent;
    }
}

function periodic(msg) {

}

function persistent(reader, start) {
    var nextSlice = reader;
    var start = start;
    var logger = _context.logger;

    return function(msg) {
        if (msg.msg === 'finished') {
            Promise.resolve(nextSlice())
                .then(function(data) {
                    //not null or undefined
                    if (data != null) {
                        sendMessage(msg.id, {message: 'data', data: data})
                    }

                })

        }
    }
}

function once(reader, start) {
    var nextSlice = reader;
    var start = start;
    var logger = _context.logger;

    return function(msg) {
        if (msg.msg === 'finished') {
            Promise.resolve(nextSlice())
                .then(function(data) {
                    //not null or undefined
                    if (data != null) {
                        sendMessage(msg.id, {message: 'data', data: data})
                    }
                    else {
                        processDone++;
                        if (processDone === workerCount) {

                            var end = moment();
                            var time = (end - start ) / 1000;

                            logger.info('processing has finished in ' + time + ' seconds, will now exit');
                            process.exit()
                        }
                    }
                })

        }
    }
}

module.exports = {
    initializeJob: initializeJob
};<commit_msg>-j works with absolute path<commit_after>'use strict';
var insertAnalyzers = require('./analytics').insertAnalyzers;
var workerCount = require('os').cpus().length;
var processDone = 0;
var moment = require('moment');
var fs = require('fs');

var _context;

var argv = require('yargs')
    .alias('j', 'job')
    .argv;

function getJob() {
    var jobFile;
    jobFile = process.cwd() + '/job.json';

    if (argv.job) {
        jobFile = argv.job;
    }
    if (!fs.existsSync(jobFile)) {
        throw new Error("Could not find a usable job.json at path: " + jobFile);
    }

    return require(jobFile);
}

function initializeJob(context) {
    _context = context;

    var job = getJob();

    var scheduler = lifecycle(job);

    var jobQueue = job.process.slice();
    var readerConfig = jobQueue.shift();
    var senderConfig = jobQueue.pop();

    var reader = require('../readers/' + readerConfig.op);
    var sender = require('../senders/' + senderConfig.op);
    var processors = jobQueue.map(function(job) {
        return require('../processors/' + job.op)
    });

    var queue = [];
    queue.push(reader.newReader(context, readerConfig));

    //using mutated jobQueue to provide opConfig
    processors.forEach(function(job, i) {
        queue.push(job.newProcessor(context, jobQueue[i]))
    });
    queue.push(sender.newSender(context, senderConfig));

    if (job.analytics) {
        queue = insertAnalyzers(queue);
    }

    return {
        analytics: job.analytics,
        reader: reader,
        sender: sender,
        processors: processors,
        jobs: job.process,
        queue: queue,
        readerConfig: readerConfig,
        scheduler: scheduler

    };
}

function sendMessage(id, message) {
    _context.cluster.workers[id].send(message);
}

function lifecycle(job) {
    if (job.lifecycle === 'once') {
        return once;
    }
    if (job.lifecycle === 'periodic') {
        return periodic;
    }
    if (job.lifecycle === 'persistent') {
        return persistent;
    }
}

function periodic(msg) {

}

function persistent(reader, start) {
    var nextSlice = reader;
    var start = start;
    var logger = _context.logger;

    return function(msg) {
        if (msg.msg === 'finished') {
            Promise.resolve(nextSlice())
                .then(function(data) {
                    //not null or undefined
                    if (data != null) {
                        sendMessage(msg.id, {message: 'data', data: data})
                    }

                })

        }
    }
}

function once(reader, start) {
    var nextSlice = reader;
    var start = start;
    var logger = _context.logger;

    return function(msg) {
        if (msg.msg === 'finished') {
            Promise.resolve(nextSlice())
                .then(function(data) {
                    //not null or undefined
                    if (data != null) {
                        sendMessage(msg.id, {message: 'data', data: data})
                    }
                    else {
                        processDone++;
                        if (processDone === workerCount) {

                            var end = moment();
                            var time = (end - start ) / 1000;

                            logger.info('processing has finished in ' + time + ' seconds, will now exit');
                            process.exit()
                        }
                    }
                })

        }
    }
}

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


<commit_before>"use strict";

const {resolve} = require("path");
const moduleDir = resolve(__dirname, "../../node_modules");
const {CompositeDisposable, Disposable} = require("atom");
const {getProperties} = require(`${moduleDir}/alhadis.utils`);

Object.defineProperties(global, {
	ed:   {get: () => atom.workspace.getActiveTextEditor()},
	pane: {get: () => atom.workspace.getActivePane()},
	sel:  {get: () => global.ed.getLastSelection()},
	cur:  {get: () => global.ed.getLastCursor()},
	tb:   {get: () => global.ed.tokenizedBuffer},
	buf:  {get: () => global.ed.buffer},
	text: {
		get: () => global.ed.buffer.getText(),
		set: to => global.ed.buffer.setText(to)
	},
	row: {
		get: () => global.cur.getBufferRow(),
		set: to => global.cur.setBufferPosition([to, global.col])
	},
	col: {
		get: () => global.cur.getBufferColumn(),
		set: to => global.cur.setBufferPosition([global.row, to])
	},
});

Object.assign(global, {
	CompositeDisposable, Disposable,
	Electron: require("electron"),
	pat:      require("path"),
	fs:       require("fs"),

	traceEmissions: (function(){
		const prot = atom.emitter.constructor.prototype;
		const emit = prot.emit;
		return function(active){
			prot.emit = !active ? emit : function(name){
				if("did-update-state" !== name)
					console.trace(arguments);
				emit.apply(this, arguments);
			};
		};
	}()),

	dispatch(command, target = null){
		target = target || atom.views.getView(atom.workspace);
		return atom.commands.dispatch(target, command);
	},

	inced(clearCache = false){
		const editor = atom.workspace.getActiveTextEditor();
		const {path} = editor.buffer.file;
		if(clearCache) delete require.cache[path];
		return require(path);
	},

	keyGrep(subject, pattern){
		pattern = "string" === typeof pattern
			? new RegExp(pattern)
			: pattern;

		const output = {};
		const props = getProperties(subject);
		for(const key of props.keys())
			if(pattern.test(key))
				output[key] = subject[key];
		return output;
	},

	loadGrammar(scope){
		return new Promise(resolve => {
			const result = atom.grammars.grammarForScopeName(scope);
			if(result) return resolve(result);
			const disposable = atom.grammars.onDidAddGrammar(grammar => {
				if(scope === grammar.scopeName){
					disposable.dispose();
					resolve(grammar);
				}
			});
		});
	},
});

// If we're accessing these on the window global,
// it means we missed something when refactoring…
["name", "path"].map(name => {
	let value = window[name];
	const zap = (action) => {
		if(window.disarmElectricShock)
			return;
		// Don't obstruct program flow. Just raise noise so I notice
		// immediately, instead of relying on other users to do so
		// for me. See file-icons/atom#469
		Promise.resolve().then(() => {
			const details =
				`If you're serious about ${action} window.${name},
				 set \`window.disarmElectricShock = true\`;
				`.replace(/\t|\n/g, "");
			setTimeout(() => console.error(details), 10);
			throw new ReferenceError("\n\tFIX YOUR DAMN BINDINGS");
		});
	};
	Object.defineProperty(window, name, {
		get: () => { zap("reading from"); return value; },
		set: to => { zap("writing to");   value = to; },
	});
});
<commit_msg>Add shortcut getter for accessing active pane item<commit_after>"use strict";

const {resolve} = require("path");
const moduleDir = resolve(__dirname, "../../node_modules");
const {CompositeDisposable, Disposable} = require("atom");
const {getProperties} = require(`${moduleDir}/alhadis.utils`);

Object.defineProperties(global, {
	ed:   {get: () => atom.workspace.getActiveTextEditor()},
	pi:   {get: () => atom.workspace.getActivePaneItem()},
	pane: {get: () => atom.workspace.getActivePane()},
	sel:  {get: () => global.ed.getLastSelection()},
	cur:  {get: () => global.ed.getLastCursor()},
	tb:   {get: () => global.ed.tokenizedBuffer},
	buf:  {get: () => global.ed.buffer},
	text: {
		get: () => global.ed.buffer.getText(),
		set: to => global.ed.buffer.setText(to)
	},
	row: {
		get: () => global.cur.getBufferRow(),
		set: to => global.cur.setBufferPosition([to, global.col])
	},
	col: {
		get: () => global.cur.getBufferColumn(),
		set: to => global.cur.setBufferPosition([global.row, to])
	},
});

Object.assign(global, {
	CompositeDisposable, Disposable,
	Electron: require("electron"),
	pat:      require("path"),
	fs:       require("fs"),

	traceEmissions: (function(){
		const prot = atom.emitter.constructor.prototype;
		const emit = prot.emit;
		return function(active){
			prot.emit = !active ? emit : function(name){
				if("did-update-state" !== name)
					console.trace(arguments);
				emit.apply(this, arguments);
			};
		};
	}()),

	dispatch(command, target = null){
		target = target || atom.views.getView(atom.workspace);
		return atom.commands.dispatch(target, command);
	},

	inced(clearCache = false){
		const editor = atom.workspace.getActiveTextEditor();
		const {path} = editor.buffer.file;
		if(clearCache) delete require.cache[path];
		return require(path);
	},

	keyGrep(subject, pattern){
		pattern = "string" === typeof pattern
			? new RegExp(pattern)
			: pattern;

		const output = {};
		const props = getProperties(subject);
		for(const key of props.keys())
			if(pattern.test(key))
				output[key] = subject[key];
		return output;
	},

	loadGrammar(scope){
		return new Promise(resolve => {
			const result = atom.grammars.grammarForScopeName(scope);
			if(result) return resolve(result);
			const disposable = atom.grammars.onDidAddGrammar(grammar => {
				if(scope === grammar.scopeName){
					disposable.dispose();
					resolve(grammar);
				}
			});
		});
	},
});

// If we're accessing these on the window global,
// it means we missed something when refactoring…
["name", "path"].map(name => {
	let value = window[name];
	const zap = (action) => {
		if(window.disarmElectricShock)
			return;
		// Don't obstruct program flow. Just raise noise so I notice
		// immediately, instead of relying on other users to do so
		// for me. See file-icons/atom#469
		Promise.resolve().then(() => {
			const details =
				`If you're serious about ${action} window.${name},
				 set \`window.disarmElectricShock = true\`;
				`.replace(/\t|\n/g, "");
			setTimeout(() => console.error(details), 10);
			throw new ReferenceError("\n\tFIX YOUR DAMN BINDINGS");
		});
	};
	Object.defineProperty(window, name, {
		get: () => { zap("reading from"); return value; },
		set: to => { zap("writing to");   value = to; },
	});
});
<|endoftext|>


<commit_before>/** @babel */
/** @jsx etch.dom */
import {CompositeDisposable} from 'atom'

import etch from 'etch'

export default class Prompt {
  constructor ({message, onSubmit, onCancel}) {
    this.message = message
    this.onSubmit = onSubmit
    this.onCancel = onCancel
    etch.initialize(this)
    this.subscriptions = new CompositeDisposable(
      atom.commands.add(this.element, 'core:cancel', () => this.cancel()),
      atom.commands.add(this.element, 'core:confirm', () => this.confirm())
    )
    setTimeout(() => this.refs.input.getElement().focus())
  }

  update () {}

  render () {
    const TextEditor = atom.workspace.buildTextEditor
    return (

{this.message}

        <TextEditor ref='input' className='git-Prompt-input' mini />

    )
  }

  confirm () {
    this.onSubmit(this.refs.input.getText())
  }

  cancel () {
    this.onCancel()
  }

  destroy (removeDomNode) {
    this.subscriptions.dispose()
    return etch.destroy(this, removeDomNode)
  }
}
<commit_msg>Import TextEditor from atom instead of using workspace.buildTextEditor<commit_after>/** @babel */
/** @jsx etch.dom */
import {CompositeDisposable, TextEditor} from 'atom'

import etch from 'etch'

export default class Prompt {
  constructor ({message, onSubmit, onCancel}) {
    this.message = message
    this.onSubmit = onSubmit
    this.onCancel = onCancel
    etch.initialize(this)
    this.subscriptions = new CompositeDisposable(
      atom.commands.add(this.element, 'core:cancel', () => this.cancel()),
      atom.commands.add(this.element, 'core:confirm', () => this.confirm())
    )
    setTimeout(() => this.refs.input.getElement().focus())
  }

  update () {}

  render () {
    return (

{this.message}

        <TextEditor ref='input' className='git-Prompt-input' mini />

    )
  }

  confirm () {
    this.onSubmit(this.refs.input.getText())
  }

  cancel () {
    this.onCancel()
  }

  destroy (removeDomNode) {
    this.subscriptions.dispose()
    return etch.destroy(this, removeDomNode)
  }
}
<|endoftext|>


<commit_before><commit_msg>Update submodule 'FileSaver.js' to the latest version<commit_after><|endoftext|>


<commit_before>/*! FileSaver.js
 *  A saveAs() FileSaver implementation.
 *  2014-01-24
 *
 *  By Eli Grey, http://eligrey.com
 *  License: X11/MIT
 *    See LICENSE.md
 */

/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */

var saveAs = saveAs
  // IE 10+ (native saveAs)
  || (typeof navigator !== "undefined" &&
      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
  // Everyone else
  || (function(view) {
	"use strict";
	// IE <10 is explicitly unsupported
	if (typeof navigator !== "undefined" &&
	    /MSIE [1-9]\./.test(navigator.userAgent)) {
		return;
	}
	var
		  doc = view.document
		  // only get URL when necessary in case BlobBuilder.js hasn't overridden it yet
		, get_URL = function() {
			return view.URL || view.webkitURL || view;
		}
		, URL = view.URL || view.webkitURL || view
		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
		, can_use_save_link = !view.externalHost && "download" in save_link
		, click = function(node) {
			var event = doc.createEvent("MouseEvents");
			event.initMouseEvent(
				"click", true, false, view, 0, 0, 0, 0, 0
				, false, false, false, false, 0, null
			);
			node.dispatchEvent(event);
		}
		, webkit_req_fs = view.webkitRequestFileSystem
		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
		, throw_outside = function(ex) {
			(view.setImmediate || view.setTimeout)(function() {
				throw ex;
			}, 0);
		}
		, force_saveable_type = "application/octet-stream"
		, fs_min_size = 0
		, deletion_queue = []
		, process_deletion_queue = function() {
			var i = deletion_queue.length;
			while (i--) {
				var file = deletion_queue[i];
				if (typeof file === "string") { // file is an object URL
					URL.revokeObjectURL(file);
				} else { // file is a File
					file.remove();
				}
			}
			deletion_queue.length = 0; // clear queue
		}
		, dispatch = function(filesaver, event_types, event) {
			event_types = [].concat(event_types);
			var i = event_types.length;
			while (i--) {
				var listener = filesaver["on" + event_types[i]];
				if (typeof listener === "function") {
					try {
						listener.call(filesaver, event || filesaver);
					} catch (ex) {
						throw_outside(ex);
					}
				}
			}
		}
		, FileSaver = function(blob, name) {
			// First try a.download, then web filesystem, then object URLs
			var
				  filesaver = this
				, type = blob.type
				, blob_changed = false
				, object_url
				, target_view
				, get_object_url = function() {
					var object_url = get_URL().createObjectURL(blob);
					deletion_queue.push(object_url);
					return object_url;
				}
				, dispatch_all = function() {
					dispatch(filesaver, "writestart progress write writeend".split(" "));
				}
				// on any filesys errors revert to saving with object URLs
				, fs_error = function() {
					// don't create more object URLs than needed
					if (blob_changed || !object_url) {
						object_url = get_object_url(blob);
					}
					if (target_view) {
						target_view.location.href = object_url;
					} else {
						window.open(object_url, "_blank");
					}
					filesaver.readyState = filesaver.DONE;
					dispatch_all();
				}
				, abortable = function(func) {
					return function() {
						if (filesaver.readyState !== filesaver.DONE) {
							return func.apply(this, arguments);
						}
					};
				}
				, create_if_not_found = {create: true, exclusive: false}
				, slice
			;
			filesaver.readyState = filesaver.INIT;
			if (!name) {
				name = "download";
			}
			if (can_use_save_link) {
				object_url = get_object_url(blob);
				// FF for Android has a nasty garbage collection mechanism
				// that turns all objects that are not pure javascript into 'deadObject'
				// this means `doc` and `save_link` are unusable and need to be recreated
				// `view` is usable though:
				doc = view.document;
				save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a");
				save_link.href = object_url;
				save_link.download = name;
				var event = doc.createEvent("MouseEvents");
				event.initMouseEvent(
					"click", true, false, view, 0, 0, 0, 0, 0
					, false, false, false, false, 0, null
				);
				save_link.dispatchEvent(event);
				filesaver.readyState = filesaver.DONE;
				dispatch_all();
				return;
			}
			// Object and web filesystem URLs have a problem saving in Google Chrome when
			// viewed in a tab, so I force save with application/octet-stream
			// http://code.google.com/p/chromium/issues/detail?id=91158
			if (view.chrome && type && type !== force_saveable_type) {
				slice = blob.slice || blob.webkitSlice;
				blob = slice.call(blob, 0, blob.size, force_saveable_type);
				blob_changed = true;
			}
			// Since I can't be sure that the guessed media type will trigger a download
			// in WebKit, I append .download to the filename.
			// https://bugs.webkit.org/show_bug.cgi?id=65440
			if (webkit_req_fs && name !== "download") {
				name += ".download";
			}
			if (type === force_saveable_type || webkit_req_fs) {
				target_view = view;
			}
			if (!req_fs) {
				fs_error();
				return;
			}
			fs_min_size += blob.size;
			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
					var save = function() {
						dir.getFile(name, create_if_not_found, abortable(function(file) {
							file.createWriter(abortable(function(writer) {
								writer.onwriteend = function(event) {
									target_view.location.href = file.toURL();
									deletion_queue.push(file);
									filesaver.readyState = filesaver.DONE;
									dispatch(filesaver, "writeend", event);
								};
								writer.onerror = function() {
									var error = writer.error;
									if (error.code !== error.ABORT_ERR) {
										fs_error();
									}
								};
								"writestart progress write abort".split(" ").forEach(function(event) {
									writer["on" + event] = filesaver["on" + event];
								});
								writer.write(blob);
								filesaver.abort = function() {
									writer.abort();
									filesaver.readyState = filesaver.DONE;
								};
								filesaver.readyState = filesaver.WRITING;
							}), fs_error);
						}), fs_error);
					};
					dir.getFile(name, {create: false}, abortable(function(file) {
						// delete file if it already exists
						file.remove();
						save();
					}), abortable(function(ex) {
						if (ex.code === ex.NOT_FOUND_ERR) {
							save();
						} else {
							fs_error();
						}
					}));
				}), fs_error);
			}), fs_error);
		}
		, FS_proto = FileSaver.prototype
		, saveAs = function(blob, name) {
			return new FileSaver(blob, name);
		}
	;
	FS_proto.abort = function() {
		var filesaver = this;
		filesaver.readyState = filesaver.DONE;
		dispatch(filesaver, "abort");
	};
	FS_proto.readyState = FS_proto.INIT = 0;
	FS_proto.WRITING = 1;
	FS_proto.DONE = 2;

	FS_proto.error =
	FS_proto.onwritestart =
	FS_proto.onprogress =
	FS_proto.onwrite =
	FS_proto.onabort =
	FS_proto.onerror =
	FS_proto.onwriteend =
		null;

	view.addEventListener("unload", process_deletion_queue, false);
	saveAs.unload = function() {
		process_deletion_queue();
		view.removeEventListener("unload", process_deletion_queue, false);
	};
	return saveAs;
}(
	   typeof self !== "undefined" && self
	|| typeof window !== "undefined" && window
	|| this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window

if (typeof module !== "undefined" && module !== null) {
  module.exports = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
  define([], function() {
    return saveAs;
  });
}
<commit_msg>Update libs/fileSaver.js<commit_after>/* FileSaver.js
 * A saveAs() FileSaver implementation.
 * 2014-08-29
 *
 * By Eli Grey, http://eligrey.com
 * License: X11/MIT
 *   See https://github.com/eligrey/FileSaver.js/blob/master/LICENSE.md
 */

/*global self */
/*jslint bitwise: true, indent: 4, laxbreak: true, laxcomma: true, smarttabs: true, plusplus: true */

/*! @source http://purl.eligrey.com/github/FileSaver.js/blob/master/FileSaver.js */

var saveAs = saveAs
  // IE 10+ (native saveAs)
  || (typeof navigator !== "undefined" &&
      navigator.msSaveOrOpenBlob && navigator.msSaveOrOpenBlob.bind(navigator))
  // Everyone else
  || (function(view) {
	"use strict";
	// IE <10 is explicitly unsupported
	if (typeof navigator !== "undefined" &&
	    /MSIE [1-9]\./.test(navigator.userAgent)) {
		return;
	}
	var
		  doc = view.document
		  // only get URL when necessary in case Blob.js hasn't overridden it yet
		, get_URL = function() {
			return view.URL || view.webkitURL || view;
		}
		, save_link = doc.createElementNS("http://www.w3.org/1999/xhtml", "a")
		, can_use_save_link = "download" in save_link
		, click = function(node) {
			var event = doc.createEvent("MouseEvents");
			event.initMouseEvent(
				"click", true, false, view, 0, 0, 0, 0, 0
				, false, false, false, false, 0, null
			);
			node.dispatchEvent(event);
		}
		, webkit_req_fs = view.webkitRequestFileSystem
		, req_fs = view.requestFileSystem || webkit_req_fs || view.mozRequestFileSystem
		, throw_outside = function(ex) {
			(view.setImmediate || view.setTimeout)(function() {
				throw ex;
			}, 0);
		}
		, force_saveable_type = "application/octet-stream"
		, fs_min_size = 0
		// See https://code.google.com/p/chromium/issues/detail?id=375297#c7 for
		// the reasoning behind the timeout and revocation flow
		, arbitrary_revoke_timeout = 10
		, revoke = function(file) {
			var revoker = function() {
				if (typeof file === "string") { // file is an object URL
					get_URL().revokeObjectURL(file);
				} else { // file is a File
					file.remove();
				}
			};
			if (view.chrome) {
				revoker();
			} else {
				setTimeout(revoker, arbitrary_revoke_timeout);
			}
		}
		, dispatch = function(filesaver, event_types, event) {
			event_types = [].concat(event_types);
			var i = event_types.length;
			while (i--) {
				var listener = filesaver["on" + event_types[i]];
				if (typeof listener === "function") {
					try {
						listener.call(filesaver, event || filesaver);
					} catch (ex) {
						throw_outside(ex);
					}
				}
			}
		}
		, FileSaver = function(blob, name) {
			// First try a.download, then web filesystem, then object URLs
			var
				  filesaver = this
				, type = blob.type
				, blob_changed = false
				, object_url
				, target_view
				, dispatch_all = function() {
					dispatch(filesaver, "writestart progress write writeend".split(" "));
				}
				// on any filesys errors revert to saving with object URLs
				, fs_error = function() {
					// don't create more object URLs than needed
					if (blob_changed || !object_url) {
						object_url = get_URL().createObjectURL(blob);
					}
					if (target_view) {
						target_view.location.href = object_url;
					} else {
						var new_tab = view.open(object_url, "_blank");
						if (new_tab == undefined && typeof safari !== "undefined") {
							//Apple do not allow window.open, see http://bit.ly/1kZffRI
							view.location.href = object_url
						}
					}
					filesaver.readyState = filesaver.DONE;
					dispatch_all();
					revoke(object_url);
				}
				, abortable = function(func) {
					return function() {
						if (filesaver.readyState !== filesaver.DONE) {
							return func.apply(this, arguments);
						}
					};
				}
				, create_if_not_found = {create: true, exclusive: false}
				, slice
			;
			filesaver.readyState = filesaver.INIT;
			if (!name) {
				name = "download";
			}
			if (can_use_save_link) {
				object_url = get_URL().createObjectURL(blob);
				save_link.href = object_url;
				save_link.download = name;
				click(save_link);
				filesaver.readyState = filesaver.DONE;
				dispatch_all();
				revoke(object_url);
				return;
			}
			// Object and web filesystem URLs have a problem saving in Google Chrome when
			// viewed in a tab, so I force save with application/octet-stream
			// http://code.google.com/p/chromium/issues/detail?id=91158
			// Update: Google errantly closed 91158, I submitted it again:
			// https://code.google.com/p/chromium/issues/detail?id=389642
			if (view.chrome && type && type !== force_saveable_type) {
				slice = blob.slice || blob.webkitSlice;
				blob = slice.call(blob, 0, blob.size, force_saveable_type);
				blob_changed = true;
			}
			// Since I can't be sure that the guessed media type will trigger a download
			// in WebKit, I append .download to the filename.
			// https://bugs.webkit.org/show_bug.cgi?id=65440
			if (webkit_req_fs && name !== "download") {
				name += ".download";
			}
			if (type === force_saveable_type || webkit_req_fs) {
				target_view = view;
			}
			if (!req_fs) {
				fs_error();
				return;
			}
			fs_min_size += blob.size;
			req_fs(view.TEMPORARY, fs_min_size, abortable(function(fs) {
				fs.root.getDirectory("saved", create_if_not_found, abortable(function(dir) {
					var save = function() {
						dir.getFile(name, create_if_not_found, abortable(function(file) {
							file.createWriter(abortable(function(writer) {
								writer.onwriteend = function(event) {
									target_view.location.href = file.toURL();
									filesaver.readyState = filesaver.DONE;
									dispatch(filesaver, "writeend", event);
									revoke(file);
								};
								writer.onerror = function() {
									var error = writer.error;
									if (error.code !== error.ABORT_ERR) {
										fs_error();
									}
								};
								"writestart progress write abort".split(" ").forEach(function(event) {
									writer["on" + event] = filesaver["on" + event];
								});
								writer.write(blob);
								filesaver.abort = function() {
									writer.abort();
									filesaver.readyState = filesaver.DONE;
								};
								filesaver.readyState = filesaver.WRITING;
							}), fs_error);
						}), fs_error);
					};
					dir.getFile(name, {create: false}, abortable(function(file) {
						// delete file if it already exists
						file.remove();
						save();
					}), abortable(function(ex) {
						if (ex.code === ex.NOT_FOUND_ERR) {
							save();
						} else {
							fs_error();
						}
					}));
				}), fs_error);
			}), fs_error);
		}
		, FS_proto = FileSaver.prototype
		, saveAs = function(blob, name) {
			return new FileSaver(blob, name);
		}
	;
	FS_proto.abort = function() {
		var filesaver = this;
		filesaver.readyState = filesaver.DONE;
		dispatch(filesaver, "abort");
	};
	FS_proto.readyState = FS_proto.INIT = 0;
	FS_proto.WRITING = 1;
	FS_proto.DONE = 2;

	FS_proto.error =
	FS_proto.onwritestart =
	FS_proto.onprogress =
	FS_proto.onwrite =
	FS_proto.onabort =
	FS_proto.onerror =
	FS_proto.onwriteend =
		null;

	return saveAs;
}(
	   typeof self !== "undefined" && self
	|| typeof window !== "undefined" && window
	|| this.content
));
// `self` is undefined in Firefox for Android content script context
// while `this` is nsIContentFrameMessageManager
// with an attribute `content` that corresponds to the window

if (typeof module !== "undefined" && module !== null) {
  module.exports = saveAs;
} else if ((typeof define !== "undefined" && define !== null) && (define.amd != null)) {
  define([], function() {
    return saveAs;
  });
}
<|endoftext|>


<commit_before>/**
 * OUI DOM library.
 *
 * @octdoc      oui/dom
 * @copyright   copyright (c) 2010-2012 by Harald Lapp
 * @author      Harald Lapp <harald@octris.org>
 */
/**/

;(function() {
    if ('dom' in oui) return;

    oui.dom = {};

    /**
     * Create DOM construct.
     *
     * @octdoc      dom/create
     * @param       string          tag             Name of tag to create.
     * @param       object          def             Definition of DOM construct to create.
     * @return      DOMElement                      Created DOM Node.
     */
    oui.dom.create = function(tag, def) {
        def = def || {};

        function _get_tag(def) {
            var tag = '';

            if (typeof def == 'object') {
                for (var i in def) {
                    tag = i;
                    break;
                }
            }

            return tag;
        }

        function _set_properties(node, def) {
            var trigger = null;
            var name, evt;

            for (var attr in def) {
                switch (attr) {
                    case 'children':
                        continue;
                    case '#trigger':
                        if (typeof def[attr] == 'function') {
                            trigger = def[attr];
                        }
                        break;
                    case '#html':
                        node.append(def[attr]);
                        break;
                    case '#text':
                        node.append(document.createTextNode(def[attr]));
                        break;
                    case '#data':
                        for (name in def[attr]) {
                            node.data(name, def[attr][name]);
                        }
                        break;
                    case 'class':
                    case 'className':
                        node.attr('className', def[attr]);
                        break;
                    case 'styles':
                    case 'css':
                        node.css(def[attr]);
                        break;
                    default:
                        if (attr.substr(0, 2) == 'on') {
                            evt = attr.substr(2).toLower();

                            if (typeof def[attr] == 'string') {
                                node.bind(evt, (function(js) {
                                    var cb = function() {
                                        eval(js);
                                    };

                                    cb.apply(node);
                                })(def[attr]));
                            } else if (typeof def[attr] == 'function') {
                                node.bind(evt, def[attr]);
                            }
                        } else {
                            node.attr(attr, def[attr]);
                        }
                }
            }

            if (trigger != null) {
                trigger(node);
            }
        }

        function _build(tag, def) {
            var i, len, tmp;

            var node = oui.$(document.createElement(tag));
            _set_properties(node, def);

            if ('children' in def && def['children'] instanceof Array) {
                for (i = 0, len = def['children'].length; i < len; ++i) {
                    if ((tmp = _get_tag(def['children'][i])) !== '') {
                        node.append(_build(tmp, def['children'][i][tmp]));
                    }
                }
            }

            return node;
        }

        return _build(tag, def);
    }
})();

<commit_msg>bugfix<commit_after>/**
 * OUI DOM library.
 *
 * @octdoc      oui/dom
 * @copyright   copyright (c) 2010-2012 by Harald Lapp
 * @author      Harald Lapp <harald@octris.org>
 */
/**/

;(function() {
    if ('dom' in oui) return;

    oui.dom = {};

    /**
     * Create DOM construct.
     *
     * @octdoc      dom/create
     * @param       string          tag             Name of tag to create.
     * @param       object          def             Definition of DOM construct to create.
     * @return      DOMElement                      Created DOM Node.
     */
    oui.dom.create = function(tag, def) {
        def = def || {};

        function _get_tag(def) {
            var tag = '';

            if (typeof def == 'object') {
                for (var i in def) {
                    tag = i;
                    break;
                }
            }

            return tag;
        }

        function _set_properties(node, def) {
            var trigger = null;
            var name, evt;

            for (var attr in def) {
                switch (attr) {
                    case 'children':
                        continue;
                    case '#trigger':
                        if (typeof def[attr] == 'function') {
                            trigger = def[attr];
                        }
                        break;
                    case '#html':
                        node.append(def[attr]);
                        break;
                    case '#text':
                        node.append(document.createTextNode(def[attr]));
                        break;
                    case '#data':
                        for (name in def[attr]) {
                            node.data(name, def[attr][name]);
                        }
                        break;
                    case 'class':
                    case 'className':
                        node.attr('class', def[attr]);
                        break;
                    case 'styles':
                    case 'css':
                        node.css(def[attr]);
                        break;
                    default:
                        if (attr.substr(0, 2) == 'on') {
                            evt = attr.substr(2).toLower();

                            if (typeof def[attr] == 'string') {
                                node.bind(evt, (function(js) {
                                    var cb = function() {
                                        eval(js);
                                    };

                                    cb.apply(node);
                                })(def[attr]));
                            } else if (typeof def[attr] == 'function') {
                                node.bind(evt, def[attr]);
                            }
                        } else {
                            node.attr(attr, def[attr]);
                        }
                }
            }

            if (trigger != null) {
                trigger(node);
            }
        }

        function _build(tag, def) {
            var i, len, tmp;

            var node = oui.$(document.createElement(tag));
            _set_properties(node, def);

            if ('children' in def && def['children'] instanceof Array) {
                for (i = 0, len = def['children'].length; i < len; ++i) {
                    if ((tmp = _get_tag(def['children'][i])) !== '') {
                        node.append(_build(tmp, def['children'][i][tmp]));
                    }
                }
            }

            return node;
        }

        return _build(tag, def);
    }
})();

<|endoftext|>