<commit_before>var bouncy = require('bouncy');
var fs = require('fs');
var _ = require('underscore');
var configPath = '/var/www/pm2config.json';
var util = require('util');
var bounceVals = {
	bouncePort: -1,
	_404Port: -1,
	servers:[]
};
var bounceServer;

var user, port;
user = parseInt(process.env.NODEUSERID) || parseInt(process.argv[2]);
if(!user){
	console.error('no user specified, exiting');
	process.exit();
}
bounceVals.bouncePort = parseInt(process.env.NODESERVERPORT) || parseInt(process.argv[3]);
if(!bounceVals.bouncePort){
	console.error('no port specified, exiting');
	process.exit();
}

console.log('starting as user: ' + process.env.USER);

fs.readFile(configPath, 'utf8', function(err, data){
	if(err){
		console.error('Error: ' + err);
		process.exit();
	}

	try{
		data = JSON.parse(data);
	} catch(e) {
		console.error('error parsing JSON.config ' + e);
		process.exit();
	}
	//console.dir(data);
	checkJSON(data);
});

function checkJSON(iJSON){
	var validParse = true;

	//test bounce server config
	var bounceConfig = _.findWhere(iJSON, {name: 'bounce-server'});
	if(typeof(bounceConfig) === 'undefined'){
		validParse = false;
		console.error('bounce server must be declared in config file');
	}

	//test 404 server config
	var _404Config = _.findWhere(iJSON, {name: '404-server'});
	if(typeof(_404Config) === 'undefined'){
		validParse = false;
		console.error('404 server must be defined in config file');
	}else if(!_404Config.env || !_404Config.env.NODESERVERPORT){
		validParse = false;
		console.error('404 server must have a valid port number');
	}else{
		bounceVals._404Port = parseInt(_404Config.env.NODESERVERPORT);
	}

	//test destination servers
	_.each(_.reject(iJSON, function(elem){
			//don't parse bounce server or 404 server again, skip non bounce items
			return (elem.name == 'bounce-server' || elem.name == '404-server' || elem.bounce != true);
		}),
		function(elem, index){
			if(typeof(elem.name) === "undefined"){
				validParse = false;
				console.error('the server in ' + index + ' place has no name');
			}
			if(!elem.env || !isValidPort(elem.env.NODESERVERPORT)){
				validParse = false;
				console.error(elem.name + ' port is invalid');
			}else{
				//valid destination server
				_.each(elem.urls, function(url, index){
					bounceVals.servers.push({
						port: parseInt(elem.env.NODESERVERPORT),
						url: elem.urls[index]
					});
				}, elem);

				if(elem.urls.length < 1){
					//no URLs allowed but print a warning
					console.error(elem.name + ' has no defined URLs');
				}
			}
		}
	);

	console.log(util.inspect(bounceVals, {depth:null}));

	if(validParse == true){
		//console.log('config parsed successfully!');
		deEscalate();
		startBounceServer();
	}else{
		console.error('problem with config file, exiting');
		process.exit();
	}
}

function deEscalate(){
	//after reading config file (root level ownership) de-escalate user permissions
	try {
		process.setuid(user);
	} catch (e) {
		console.error('problem setting user, exiting');
		console.dir(e);
		process.exit();
	}
	console.log('user changed to: ' + process.env.USER);
}

function startBounceServer(){
	bounceServer = bouncy(function(req, res, bounce){
		var foundMatch = false;
		var baseHost = trimAt(req.headers.host,':');
		console.log('incoming request for: ' + baseHost);
		console.log('incoming client IP addr: ' + getClientIP(req));
		for(var rep=0;rep<bounceVals.servers.length;rep++){
			//console.log(bounceVals.servers[rep].url);
			if(bounceVals.servers[rep].url == baseHost){
				console.log('loading ' + baseHost);
				bounce(bounceVals.servers[rep].port);
				foundMatch = true;
			}
		}
		if(foundMatch == false){
			console.log('404! ' + baseHost);
			bounce(bounceVals._404Port);
		}
	});

	//engage server
	console.log(bounceVals.bouncePort);
	bounceServer.listen(bounceVals.bouncePort);
	console.log('bounce listening at: ' + bounceVals.bouncePort);
}

function isNumber(iNum){
	return !isNaN(parseFloat(iNum)) && isFinite(iNum);
}

function isValidPort(iNum){
	return isNumber(iNum) && (iNum > 0) && (iNum < 65536) && (iNum = Math.floor(iNum));
}

function trimAt(iString, iChar){
	if(typeof iString === 'undefined') {return ('null string');}
	var pos = iString.indexOf(iChar);
	if(pos > -1){
		return iString.substring(0, pos);
	}
	return iString;
}

function getClientIP(req){
	var ipAddress = req.headers['x-forwarded-for'];
	if(ipAddress) {return ipAddress[0];}
	else {ipAddress = req.connection.remoteAddress;}
	return ipAddress;
}
<commit_msg>added group de-escalation<commit_after>var bouncy = require('bouncy');
var fs = require('fs');
var _ = require('underscore');
var configPath = '/var/www/pm2config.json';
var util = require('util');
var bounceVals = {
	bouncePort: -1,
	_404Port: -1,
	servers:[]
};
var bounceServer;

var user, port;
user = parseInt(process.env.NODEUSERID) || parseInt(process.argv[2]);
if(!user){
	console.error('no user specified, exiting');
	process.exit();
}
bounceVals.bouncePort = parseInt(process.env.NODESERVERPORT) || parseInt(process.argv[3]);
if(!bounceVals.bouncePort){
	console.error('no port specified, exiting');
	process.exit();
}

console.log('starting as user: ' + process.env.USER);

fs.readFile(configPath, 'utf8', function(err, data){
	if(err){
		console.error('Error: ' + err);
		process.exit();
	}

	try{
		data = JSON.parse(data);
	} catch(e) {
		console.error('error parsing JSON.config ' + e);
		process.exit();
	}
	//console.dir(data);
	checkJSON(data);
});

function checkJSON(iJSON){
	var validParse = true;

	//test bounce server config
	var bounceConfig = _.findWhere(iJSON, {name: 'bounce-server'});
	if(typeof(bounceConfig) === 'undefined'){
		validParse = false;
		console.error('bounce server must be declared in config file');
	}

	//test 404 server config
	var _404Config = _.findWhere(iJSON, {name: '404-server'});
	if(typeof(_404Config) === 'undefined'){
		validParse = false;
		console.error('404 server must be defined in config file');
	}else if(!_404Config.env || !_404Config.env.NODESERVERPORT){
		validParse = false;
		console.error('404 server must have a valid port number');
	}else{
		bounceVals._404Port = parseInt(_404Config.env.NODESERVERPORT);
	}

	//test destination servers
	_.each(_.reject(iJSON, function(elem){
			//don't parse bounce server or 404 server again, skip non bounce items
			return (elem.name == 'bounce-server' || elem.name == '404-server' || elem.bounce != true);
		}),
		function(elem, index){
			if(typeof(elem.name) === "undefined"){
				validParse = false;
				console.error('the server in ' + index + ' place has no name');
			}
			if(!elem.env || !isValidPort(elem.env.NODESERVERPORT)){
				validParse = false;
				console.error(elem.name + ' port is invalid');
			}else{
				//valid destination server
				_.each(elem.urls, function(url, index){
					bounceVals.servers.push({
						port: parseInt(elem.env.NODESERVERPORT),
						url: elem.urls[index]
					});
				}, elem);

				if(elem.urls.length < 1){
					//no URLs allowed but print a warning
					console.error(elem.name + ' has no defined URLs');
				}
			}
		}
	);

	console.log(util.inspect(bounceVals, {depth:null}));

	if(validParse == true){
		//console.log('config parsed successfully!');
		deEscalate();
		startBounceServer();
	}else{
		console.error('problem with config file, exiting');
		process.exit();
	}
}

function deEscalate(){
	//after reading config file (root level ownership) de-escalate user permissions
	try {
		process.setuid(user);
		process.setgid(user);
	} catch (e) {
		console.error('problem setting user/group, exiting');
		console.dir(e);
		process.exit();
	}
	console.log('user changed to: ' + process.env.USER);
}

function startBounceServer(){
	bounceServer = bouncy(function(req, res, bounce){
		var foundMatch = false;
		var baseHost = trimAt(req.headers.host,':');
		console.log('incoming request for: ' + baseHost);
		console.log('incoming client IP addr: ' + getClientIP(req));
		for(var rep=0;rep<bounceVals.servers.length;rep++){
			//console.log(bounceVals.servers[rep].url);
			if(bounceVals.servers[rep].url == baseHost){
				console.log('loading ' + baseHost);
				bounce(bounceVals.servers[rep].port);
				foundMatch = true;
			}
		}
		if(foundMatch == false){
			console.log('404! ' + baseHost);
			bounce(bounceVals._404Port);
		}
	});

	//engage server
	console.log(bounceVals.bouncePort);
	bounceServer.listen(bounceVals.bouncePort);
	console.log('bounce listening at: ' + bounceVals.bouncePort);
}

function isNumber(iNum){
	return !isNaN(parseFloat(iNum)) && isFinite(iNum);
}

function isValidPort(iNum){
	return isNumber(iNum) && (iNum > 0) && (iNum < 65536) && (iNum = Math.floor(iNum));
}

function trimAt(iString, iChar){
	if(typeof iString === 'undefined') {return ('null string');}
	var pos = iString.indexOf(iChar);
	if(pos > -1){
		return iString.substring(0, pos);
	}
	return iString;
}

function getClientIP(req){
	var ipAddress = req.headers['x-forwarded-for'];
	if(ipAddress) {return ipAddress[0];}
	else {ipAddress = req.connection.remoteAddress;}
	return ipAddress;
}
<|endoftext|>


<commit_before>var express = require("express");
var app = express();

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    // what about X-Requested-With, X-HTTP-Method-Override, Accept ?

    if (req.method === 'OPTIONS') {
        res.end();
    } else {
        next();
    }
};

var sendJSON = function(req, res, next) {
    res.header('Content-Type', 'application/json; charset=UTF-8');
    next();
};

var whitelist = function(req, res, next) {
    if (req && req.params && req.params.hasOwnProperty('username')) {
        var username = req.params.username;
        if (app.get('state').config.whitelist.hasOwnProperty(username)) {
            req.username = username;
            next();
        }
    }
    res.send(200, [
        {
            error: {
                type: 1,
                address: '/',
                description: 'unauthorized user'
            }
        }
    ]);
};

app.use(express.logger());
app.use(express.static(__dirname + '/public_html'));
app.use(express.bodyParser());
app.use(allowCrossDomain);
app.use(sendJSON);

app.set('state', {
    "lights": {
        "1": {
            "state": {
                "on": false,
                "bri": 0,
                "hue": 0,
                "sat": 0,
                "xy": [0.0000, 0.0000],
                "ct": 0,
                "alert": "none",
                "effect": "none",
                "colormode": "hs",
                "reachable": true
            },
            "type": "Extended color light",
            "name": "Hue Lamp 1",
            "modelid": "LCT001",
            "swversion": "65003148",
            "pointsymbol": {
                "1": "none",
                "2": "none",
                "3": "none",
                "4": "none",
                "5": "none",
                "6": "none",
                "7": "none",
                "8": "none"
            }
        },
        "2": {
            "state": {
                "on": true,
                "bri": 254,
                "hue": 33536,
                "sat": 144,
                "xy": [0.3460, 0.3568],
                "ct": 201,
                "alert": "none",
                "effect": "none",
                "colormode": "hs",
                "reachable": true
            },
            "type": "Extended color light",
            "name": "Hue Lamp 2",
            "modelid": "LCT001",
            "swversion": "65003148",
            "pointsymbol": {
                "1": "none",
                "2": "none",
                "3": "none",
                "4": "none",
                "5": "none",
                "6": "none",
                "7": "none",
                "8": "none"
            }
        }
    },
    "groups": {
        "1": {
            "action": {
                "on": true,
                "bri": 254,
                "hue": 33536,
                "sat": 144,
                "xy": [0.3460, 0.3568],
                "ct": 201,
                "effect": "none",
                "colormode": "xy"
            },
            "lights": ["1", "2"],
            "name": "Group 1"
        }
    },
    "config": {
        "name": "Philips hue",
        "mac": "00:00:88:00:bb:ee",
        "dhcp": true,
        "ipaddress": "192.168.1.74",
        "netmask": "255.255.255.0",
        "gateway": "192.168.1.254",
        "proxyaddress": "",
        "proxyport": 0,
        "UTC": "2012-10-29T12:00:00",
        "whitelist": {
            "newdeveloper": {
                "last use date": "2012-10-29T12:00:00",
                "create date": "2012-10-29T12:00:00",
                "name": "test user"
            }
        },
        "swversion": "01003542",
        "swupdate": {
            "updatestate": 0,
            "url": "",
            "text": "",
            "notify": false
        },
        "linkbutton": false,
        "portalservices": false
    },
    "schedules": {
        "1": {
            "name": "schedule",
            "description": "",
            "command": {
                "address": "/api/0/groups/0/action",
                "body": {
                    "on": true
                },
                "method": "PUT"
            },
            "time": "2012-10-29T12:00:00"
        }
    }
});

app.get('/', function(req, res) {
    res.redirect(301, 'index.html');
});

app.get('/linkbutton', function(request, response) {
    app.get('state').config.linkbutton = true;
    setTimeout(function() {
        app.get('state').config.linkbutton = false;
    }, 30000);
    response.send(200, "link button pushed. you have 30 seconds to register new usernames");
});

// -- Lights API

// get all lights
app.get('/api/:username/lights', whitelist, function(req, res) {
    // get light state
    var lights = app.get('state').lights;
    // only send names of lights
    var result = mapObject(lights, function(light) {
        return selectSubsetFromJSON(light, 'name');
    });
    res.send(200, JSON.stringify(result));
});

var mapObject = function(obj, fn) {
    var result = {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = fn(obj[key]);
        }
    }
    return result;
};

var selectSubsetFromJSON = function(json, keys) {
    var result = {};
    // cast 'keys' to array
    if (typeof keys !== 'object') {
        keys = [keys];
    }
    for (var i = 0; i < keys.length; i++) {
        result[keys[i]] = json[keys[i]];
    }
    return result;
};

// get new lights TODO
app.get('/api/:username/lights/new', whitelist, function(req, res) {
    res.send(200, JSON.stringify({
        "7": {
            "name": "Hue Lamp 7"
        },
        "8": {
            "name": "Hue Lamp 8"
        },
        "lastscan": "2012-10-29T12:00:00"
    }));
});

// search for new lights TODO
// accept a new light object and add it to lights list
// since this isn't a real feature of the Hue bridge API, didn't modify the return value
app.post('/api/:username/lights', whitelist, function(req, res) {
    //figure out next index
    var numKeys = Object.keys(app.get('state').lights).length;
    //Clone one of the existing objects as a placeholder at the new index
    app.get('state').lights[numKeys + 1] = JSON.parse(JSON.stringify(app.get('state').lights[1]));
    var newLight = app.get('state').lights[numKeys + 1];
    //update name
    if(req.body.name != null && req.body.name != undefined){
    	newLight.name = req.body.name;
    }
    //update state
    updateProperties(newLight.state,req.body.state,null);
    res.send(200, JSON.stringify([{"success": {"/lights": "Searching for new devices"}}]));
});

// get light
app.get('/api/:username/lights/:id', whitelist, function(req, res) {
    var id = req.params.id;
    res.send(200, JSON.stringify(app.get('state').lights[id]));
});

// rename light
app.put('/api/:username/lights/:id', whitelist, function(req, res) {
    var name = req.body.name;
    var id = req.params.id;
    app.get('state').lights[id]["name"] = name;
    var success = {};
    success["/lights/" + id + "/name"] = name;
    res.send(200, JSON.stringify([{"success": success}]));
});

// change light state
app.put('/api/:username/lights/:id/state', whitelist, function(req, res) {
    var id = req.params.id;
    var state = app.get('state').lights[id].state;
    var response = updateProperties(state, req.body, "/lights/" + id + "/state/");
    res.send(200, JSON.stringify(response));
});

var updateProperties = function(obj, props, successPath) {
    var response = [];
    for (var propertyToBeUpdated in props) {
        if (props.hasOwnProperty(propertyToBeUpdated)) {
            if (obj.hasOwnProperty(propertyToBeUpdated)) {
                var newValue = props[propertyToBeUpdated];
                obj[propertyToBeUpdated] = newValue;
                // TODO: currently all values are treated as string ! this could lead to bugs and has to be fixed
                if (successPath) {
                    var success = {};
                    success[successPath + propertyToBeUpdated] = newValue;
                    response.push({
                        "success": success
                    });
                }
            }
        }
    }
    return response;
};

// -- Groups API

// get groups
app.get('/api/:username/groups', whitelist, function(req, res) {
    // get light state
    var groups = app.get('state').groups;
    // only send names of lights
    var result = mapObject(groups, function(group) {
        return selectSubsetFromJSON(group, 'name');
    });
    res.send(200, JSON.stringify(result));
});

// get group attributes
app.get('/api/:username/groups/:id', whitelist, function(req, res) {
    var id = req.params.id;
    res.send(200, JSON.stringify(app.get('state').groups[id]));
});

// set group attributes
app.put('/api/:username/groups/:id', whitelist, function(req, res) {
    var id = req.params.id;
    var name = req.body.name;
    var lights = req.body.lights;
    var group = app.get('state').groups[id];
    var result = [];

    if (name) {
        group.name = name;
        var success = {};
        success["/groups/" + id + "/name"] = name;
        result.push({"success": success});
    }

    if (lights) {
        group.lights = lights;
        var success = {};
        success["/groups/" + id + "/lights"] = lights;
        result.push({"success": success});
    }

    res.send(200, JSON.stringify(result));
});

// set group state
app.put('/api/:username/groups/:id/action', whitelist, function(req, res) {
    var id = req.params.id;
    var action = req.body;
    var group = app.get('state').groups[id];

    var lights = [];
    if (id === '0') {
        for (var lightId in app.get('state').lights) {
            lights.push(lightId);
        }
    } else {
        if (group) {
            lights = group.lights;
            group.action = action;
        } else {
            // error TODO proper handling
            console.error("no group found");
        }
    }

    for (var i = 0; i < lights.length; i++) {
        var lightId = lights[i];
        var lightState = app.get('state').lights[lightId].state;
        updateProperties(lightState, action);
    }

    var result = [];
    for (var property in action) {
        var success = {};
        success["/groups/" + id + "/action/" + property] = action[property];
        result.push({"success": success});
    }

    res.send(200, JSON.stringify(result));
});

// -- Configuration API

// create user
app.post('/api', function(request, response) {
    var devicetype = request.body.devicetype;
    var username = request.body.username;
    if (!username) {
        username = "letmegeneratethatforyou";
    }
    if (app.get('state').config.linkbutton) {
        app.get('state').config.whitelist[username] = {
            "last use date": "2012-10-29T12:00:00",
            "create date": "2012-10-29T12:00:00",
            "name": devicetype
        };
        response.send(200, JSON.stringify([
            {
                success: {
                    "username": username
                }
            }
        ]));
    } else {
        response.send(200, JSON.stringify([
            {
                error: {
                    type: 101,
                    address: '',
                    description: 'link button not pressed'
                }
            }
        ]));
    }
});

// get config
app.get('/api/:username/config', function(req, res) {
    // config does not give unauthorized_user error, but a public part of the config
    if (req && req.params && req.params.hasOwnProperty('username')) {
        var username = req.params.username;
        if (app.get('state').config.whitelist.hasOwnProperty(username)) {
            res.send(200, JSON.stringify(app.get('state').config));
        }
    }
    // only send name and swversion if the user is not authed
    res.send(200, JSON.stringify(selectSubsetFromJSON(app.get('state').config, ['name', 'swversion'])));
});

// change config
app.put('/api/:username/config', whitelist, function(request, response) {
    var result = updateProperties(app.get('state').config, request.body, "/config/");
    response.send(200, JSON.stringify(result));
});

// delete user
app.delete('/api/:username/config/whitelist/:userToBeDeleted', whitelist, function(req, res) {
    var deleteUsername = req.params.userToBeDeleted;
    delete app.get('state').config.whitelist[deleteUsername];
    res.send(200, JSON.stringify([{"success": "/config/whitelist/" + deleteUsername + " deleted."}]));
});

// get full state
app.get('/api/:username', whitelist, function(request, response) {
    response.send(200, JSON.stringify(app.get('state')));
});

module.exports = app;
<commit_msg>Check for empty object<commit_after>var express = require("express");
var app = express();

var allowCrossDomain = function(req, res, next) {
    res.header('Access-Control-Allow-Origin', '*');
    res.header('Access-Control-Allow-Methods', 'GET, PUT, POST, DELETE, OPTIONS');
    res.header('Access-Control-Allow-Headers', 'Content-Type');
    // what about X-Requested-With, X-HTTP-Method-Override, Accept ?

    if (req.method === 'OPTIONS') {
        res.end();
    } else {
        next();
    }
};

var sendJSON = function(req, res, next) {
    res.header('Content-Type', 'application/json; charset=UTF-8');
    next();
};

var whitelist = function(req, res, next) {
    if (req && req.params && req.params.hasOwnProperty('username')) {
        var username = req.params.username;
        if (app.get('state').config.whitelist.hasOwnProperty(username)) {
            req.username = username;
            next();
        }
    }
    res.send(200, [
        {
            error: {
                type: 1,
                address: '/',
                description: 'unauthorized user'
            }
        }
    ]);
};

app.use(express.logger());
app.use(express.static(__dirname + '/public_html'));
app.use(express.bodyParser());
app.use(allowCrossDomain);
app.use(sendJSON);

app.set('state', {
    "lights": {
        "1": {
            "state": {
                "on": false,
                "bri": 0,
                "hue": 0,
                "sat": 0,
                "xy": [0.0000, 0.0000],
                "ct": 0,
                "alert": "none",
                "effect": "none",
                "colormode": "hs",
                "reachable": true
            },
            "type": "Extended color light",
            "name": "Hue Lamp 1",
            "modelid": "LCT001",
            "swversion": "65003148",
            "pointsymbol": {
                "1": "none",
                "2": "none",
                "3": "none",
                "4": "none",
                "5": "none",
                "6": "none",
                "7": "none",
                "8": "none"
            }
        },
        "2": {
            "state": {
                "on": true,
                "bri": 254,
                "hue": 33536,
                "sat": 144,
                "xy": [0.3460, 0.3568],
                "ct": 201,
                "alert": "none",
                "effect": "none",
                "colormode": "hs",
                "reachable": true
            },
            "type": "Extended color light",
            "name": "Hue Lamp 2",
            "modelid": "LCT001",
            "swversion": "65003148",
            "pointsymbol": {
                "1": "none",
                "2": "none",
                "3": "none",
                "4": "none",
                "5": "none",
                "6": "none",
                "7": "none",
                "8": "none"
            }
        }
    },
    "groups": {
        "1": {
            "action": {
                "on": true,
                "bri": 254,
                "hue": 33536,
                "sat": 144,
                "xy": [0.3460, 0.3568],
                "ct": 201,
                "effect": "none",
                "colormode": "xy"
            },
            "lights": ["1", "2"],
            "name": "Group 1"
        }
    },
    "config": {
        "name": "Philips hue",
        "mac": "00:00:88:00:bb:ee",
        "dhcp": true,
        "ipaddress": "192.168.1.74",
        "netmask": "255.255.255.0",
        "gateway": "192.168.1.254",
        "proxyaddress": "",
        "proxyport": 0,
        "UTC": "2012-10-29T12:00:00",
        "whitelist": {
            "newdeveloper": {
                "last use date": "2012-10-29T12:00:00",
                "create date": "2012-10-29T12:00:00",
                "name": "test user"
            }
        },
        "swversion": "01003542",
        "swupdate": {
            "updatestate": 0,
            "url": "",
            "text": "",
            "notify": false
        },
        "linkbutton": false,
        "portalservices": false
    },
    "schedules": {
        "1": {
            "name": "schedule",
            "description": "",
            "command": {
                "address": "/api/0/groups/0/action",
                "body": {
                    "on": true
                },
                "method": "PUT"
            },
            "time": "2012-10-29T12:00:00"
        }
    }
});

app.get('/', function(req, res) {
    res.redirect(301, 'index.html');
});

app.get('/linkbutton', function(request, response) {
    app.get('state').config.linkbutton = true;
    setTimeout(function() {
        app.get('state').config.linkbutton = false;
    }, 30000);
    response.send(200, "link button pushed. you have 30 seconds to register new usernames");
});

// -- Lights API

// get all lights
app.get('/api/:username/lights', whitelist, function(req, res) {
    // get light state
    var lights = app.get('state').lights;
    // only send names of lights
    var result = mapObject(lights, function(light) {
        return selectSubsetFromJSON(light, 'name');
    });
    res.send(200, JSON.stringify(result));
});

var mapObject = function(obj, fn) {
    var result = {};
    for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = fn(obj[key]);
        }
    }
    return result;
};

var selectSubsetFromJSON = function(json, keys) {
    var result = {};
    // cast 'keys' to array
    if (typeof keys !== 'object') {
        keys = [keys];
    }
    for (var i = 0; i < keys.length; i++) {
        result[keys[i]] = json[keys[i]];
    }
    return result;
};

// get new lights TODO
app.get('/api/:username/lights/new', whitelist, function(req, res) {
    res.send(200, JSON.stringify({
        "7": {
            "name": "Hue Lamp 7"
        },
        "8": {
            "name": "Hue Lamp 8"
        },
        "lastscan": "2012-10-29T12:00:00"
    }));
});

// search for new lights TODO
// accept a new light object and add it to lights list
// since this isn't a real feature of the Hue bridge API, didn't modify the return value
app.post('/api/:username/lights', whitelist, function(req, res) {
    if(req.body && req.body.length > 0){
        //figure out next index
        var numKeys = Object.keys(app.get('state').lights).length;
        //Clone one of the existing objects as a placeholder at the new index
        app.get('state').lights[numKeys + 1] = JSON.parse(JSON.stringify(app.get('state').lights[1]));
        var newLight = app.get('state').lights[numKeys + 1];
        //update name
        if(req.body.name != null && req.body.name != undefined){
        	newLight.name = req.body.name;
        }
        //update state
        updateProperties(newLight.state,req.body.state,null);
    }
    res.send(200, JSON.stringify([{"success": {"/lights": "Searching for new devices"}}]));
});

// get light
app.get('/api/:username/lights/:id', whitelist, function(req, res) {
    var id = req.params.id;
    res.send(200, JSON.stringify(app.get('state').lights[id]));
});

// rename light
app.put('/api/:username/lights/:id', whitelist, function(req, res) {
    var name = req.body.name;
    var id = req.params.id;
    app.get('state').lights[id]["name"] = name;
    var success = {};
    success["/lights/" + id + "/name"] = name;
    res.send(200, JSON.stringify([{"success": success}]));
});

// change light state
app.put('/api/:username/lights/:id/state', whitelist, function(req, res) {
    var id = req.params.id;
    var state = app.get('state').lights[id].state;
    var response = updateProperties(state, req.body, "/lights/" + id + "/state/");
    res.send(200, JSON.stringify(response));
});

var updateProperties = function(obj, props, successPath) {
    var response = [];
    for (var propertyToBeUpdated in props) {
        if (props.hasOwnProperty(propertyToBeUpdated)) {
            if (obj.hasOwnProperty(propertyToBeUpdated)) {
                var newValue = props[propertyToBeUpdated];
                obj[propertyToBeUpdated] = newValue;
                // TODO: currently all values are treated as string ! this could lead to bugs and has to be fixed
                if (successPath) {
                    var success = {};
                    success[successPath + propertyToBeUpdated] = newValue;
                    response.push({
                        "success": success
                    });
                }
            }
        }
    }
    return response;
};

// -- Groups API

// get groups
app.get('/api/:username/groups', whitelist, function(req, res) {
    // get light state
    var groups = app.get('state').groups;
    // only send names of lights
    var result = mapObject(groups, function(group) {
        return selectSubsetFromJSON(group, 'name');
    });
    res.send(200, JSON.stringify(result));
});

// get group attributes
app.get('/api/:username/groups/:id', whitelist, function(req, res) {
    var id = req.params.id;
    res.send(200, JSON.stringify(app.get('state').groups[id]));
});

// set group attributes
app.put('/api/:username/groups/:id', whitelist, function(req, res) {
    var id = req.params.id;
    var name = req.body.name;
    var lights = req.body.lights;
    var group = app.get('state').groups[id];
    var result = [];

    if (name) {
        group.name = name;
        var success = {};
        success["/groups/" + id + "/name"] = name;
        result.push({"success": success});
    }

    if (lights) {
        group.lights = lights;
        var success = {};
        success["/groups/" + id + "/lights"] = lights;
        result.push({"success": success});
    }

    res.send(200, JSON.stringify(result));
});

// set group state
app.put('/api/:username/groups/:id/action', whitelist, function(req, res) {
    var id = req.params.id;
    var action = req.body;
    var group = app.get('state').groups[id];

    var lights = [];
    if (id === '0') {
        for (var lightId in app.get('state').lights) {
            lights.push(lightId);
        }
    } else {
        if (group) {
            lights = group.lights;
            group.action = action;
        } else {
            // error TODO proper handling
            console.error("no group found");
        }
    }

    for (var i = 0; i < lights.length; i++) {
        var lightId = lights[i];
        var lightState = app.get('state').lights[lightId].state;
        updateProperties(lightState, action);
    }

    var result = [];
    for (var property in action) {
        var success = {};
        success["/groups/" + id + "/action/" + property] = action[property];
        result.push({"success": success});
    }

    res.send(200, JSON.stringify(result));
});

// -- Configuration API

// create user
app.post('/api', function(request, response) {
    var devicetype = request.body.devicetype;
    var username = request.body.username;
    if (!username) {
        username = "letmegeneratethatforyou";
    }
    if (app.get('state').config.linkbutton) {
        app.get('state').config.whitelist[username] = {
            "last use date": "2012-10-29T12:00:00",
            "create date": "2012-10-29T12:00:00",
            "name": devicetype
        };
        response.send(200, JSON.stringify([
            {
                success: {
                    "username": username
                }
            }
        ]));
    } else {
        response.send(200, JSON.stringify([
            {
                error: {
                    type: 101,
                    address: '',
                    description: 'link button not pressed'
                }
            }
        ]));
    }
});

// get config
app.get('/api/:username/config', function(req, res) {
    // config does not give unauthorized_user error, but a public part of the config
    if (req && req.params && req.params.hasOwnProperty('username')) {
        var username = req.params.username;
        if (app.get('state').config.whitelist.hasOwnProperty(username)) {
            res.send(200, JSON.stringify(app.get('state').config));
        }
    }
    // only send name and swversion if the user is not authed
    res.send(200, JSON.stringify(selectSubsetFromJSON(app.get('state').config, ['name', 'swversion'])));
});

// change config
app.put('/api/:username/config', whitelist, function(request, response) {
    var result = updateProperties(app.get('state').config, request.body, "/config/");
    response.send(200, JSON.stringify(result));
});

// delete user
app.delete('/api/:username/config/whitelist/:userToBeDeleted', whitelist, function(req, res) {
    var deleteUsername = req.params.userToBeDeleted;
    delete app.get('state').config.whitelist[deleteUsername];
    res.send(200, JSON.stringify([{"success": "/config/whitelist/" + deleteUsername + " deleted."}]));
});

// get full state
app.get('/api/:username', whitelist, function(request, response) {
    response.send(200, JSON.stringify(app.get('state')));
});

module.exports = app;
<|endoftext|>


<commit_before>process.exit(

     0.00 // budget.js - keeping the books for @brooklyn_js
          // by @jedschmidt and @brianloveswords

          // for details, see our accountant:
          // https://travis-ci.org/brooklynjs/brooklynjs.github.io

          // BrooklynJS #1, 2013-11-14T19:00Z at @61Local
          // featuring @nakajima, @jandet, @SaraJChipps, and @jeresig

+  360.00 // ticket sales  @peatix
+  350.00 // sponsorship   @github

-  360.00 // bar tab       @61local
-   81.00 // ticketing     @peatix
-   51.00 // banners       @BuildASign
-   50.00 // venue         @61local
-   32.00 // VGA adapter   @amazon
-   21.00 // nametags      @staples
-   14.00 // domain        @namecheap

-   50.50 // donation      @GirlsWhoCode
-   50.50 // donation      @ScriptEdOrg

          // BrooklynJS #2, 2013-12-16T19:00Z at @61Local
          // featuring @tbuchok, @vinceallenvince, @buritica, @benjamn, and @reconbot
          // with special musical guest, @jedschmidt's barbershop quartet, the four fives

+  665.00 // ticket sales  @peatix
+  450.00 // sponsorship   @crushlovely

-  644.38 // bar tab       @61local
-  107.00 // ticketing     @peatix
-   65.18 // stickers      @diginate
-   50.00 // venue         @61local
-   29.55 // VGA cable     @amazon
-    7.49 // paper tickets @amazon

-  105.70 // donation      @GirlsWhoCode
-  105.70 // donation      @ScriptEdOrg

          // BrooklynJS #3, 2014-01-22T19:00Z at @61Local
          // featuring @thlorenz, @donohoe, @mathisonian, and @jennschiffer
          // with special musical guest, @csvsoundsystem

+  970.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @nodejitsu, @digitalocean, and @harvest

-  800.00 // bar tab       @61local
-  136.99 // ticketing     @peatix
-  237.57 // tokens        @CuboNewYork521
-   79.59 // stickers      @diginate
-   50.00 // venue         @61local
-   10.99 // 3.5mm cable   @amazon

-  577.43 // donation      @GirlsWhoCode
-  577.43 // donation      @ScriptEdOrg

          // BrooklynJS #4, 2014-02-20T19:00Z at @61Local
          // featuring @amasad, @coderzach, @maryrosecook, @rich_harris, and @susanemcg
          // with special musical guest, @thlorenz

+ 1210.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @etsy, @hugeinc, and @bocoup

-  360.00 // bar tab       @61local
-  163.78 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-   50.00 // venue         @61local
-   18.61 // nametags      @staples

- 1923.59 // donation      @ScriptEdOrg

          // BrooklynJS #5, 2014-03-20T19:00Z at @61Local
	  // featuring @domenic, @opheliasdaisies, @brycekahle, @frazelledazzell, and @kirbysayshi
          // with special musical guest, @jedschmidt's barbershop quartet, the four fives

+ 1590.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @digitalocean, @tumblreng, and @sfxii

-  460.00 // bar tab       @61local
-  400.00 // food          @61local
-  195.00 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-   64.41 // stickers      @diginate
-   56.76 // cables        @amazon
-   50.00 // venue         @61local
-   28.26 // nametags      @amazon
-   23.99 // KVM switch    @amazon

-  808.78 // donation      @GirlsWhoCode
-  808.78 // donation      @ScriptEdOrg

	  // BrooklynJS #6, 2014-04-17T19:00Z at @61Local
	  // featuring @donohoe, @dphiffer, @__lucas, @danordille, and @sarajchipps
	  // with special musical guest, bathtub jen and the henchmen

+ 1690.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @spotify, @twilio, and @chartbeat

-  450.00 // bar tab       @61local
-  400.00 // food          @61local
-  200.00 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-  160.00 // entertainment
-   50.00 // venue         @61local

-  867.99 // donation      @GirlsWhoCode
-  867.99 // donation      @ScriptEdOrg

)
<commit_msg>tabs v space, i don't even.<commit_after>process.exit(

     0.00 // budget.js - keeping the books for @brooklyn_js
          // by @jedschmidt and @brianloveswords

          // for details, see our accountant:
          // https://travis-ci.org/brooklynjs/brooklynjs.github.io

          // BrooklynJS #1, 2013-11-14T19:00Z at @61Local
          // featuring @nakajima, @jandet, @SaraJChipps, and @jeresig

+  360.00 // ticket sales  @peatix
+  350.00 // sponsorship   @github

-  360.00 // bar tab       @61local
-   81.00 // ticketing     @peatix
-   51.00 // banners       @BuildASign
-   50.00 // venue         @61local
-   32.00 // VGA adapter   @amazon
-   21.00 // nametags      @staples
-   14.00 // domain        @namecheap

-   50.50 // donation      @GirlsWhoCode
-   50.50 // donation      @ScriptEdOrg

          // BrooklynJS #2, 2013-12-16T19:00Z at @61Local
          // featuring @tbuchok, @vinceallenvince, @buritica, @benjamn, and @reconbot
          // with special musical guest, @jedschmidt's barbershop quartet, the four fives

+  665.00 // ticket sales  @peatix
+  450.00 // sponsorship   @crushlovely

-  644.38 // bar tab       @61local
-  107.00 // ticketing     @peatix
-   65.18 // stickers      @diginate
-   50.00 // venue         @61local
-   29.55 // VGA cable     @amazon
-    7.49 // paper tickets @amazon

-  105.70 // donation      @GirlsWhoCode
-  105.70 // donation      @ScriptEdOrg

          // BrooklynJS #3, 2014-01-22T19:00Z at @61Local
          // featuring @thlorenz, @donohoe, @mathisonian, and @jennschiffer
          // with special musical guest, @csvsoundsystem

+  970.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @nodejitsu, @digitalocean, and @harvest

-  800.00 // bar tab       @61local
-  136.99 // ticketing     @peatix
-  237.57 // tokens        @CuboNewYork521
-   79.59 // stickers      @diginate
-   50.00 // venue         @61local
-   10.99 // 3.5mm cable   @amazon

-  577.43 // donation      @GirlsWhoCode
-  577.43 // donation      @ScriptEdOrg

          // BrooklynJS #4, 2014-02-20T19:00Z at @61Local
          // featuring @amasad, @coderzach, @maryrosecook, @rich_harris, and @susanemcg
          // with special musical guest, @thlorenz

+ 1210.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @etsy, @hugeinc, and @bocoup

-  360.00 // bar tab       @61local
-  163.78 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-   50.00 // venue         @61local
-   18.61 // nametags      @staples

- 1923.59 // donation      @ScriptEdOrg

          // BrooklynJS #5, 2014-03-20T19:00Z at @61Local
          // featuring @domenic, @opheliasdaisies, @brycekahle, @frazelledazzell, and @kirbysayshi
          // with special musical guest, @jedschmidt's barbershop quartet, the four fives

+ 1590.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @digitalocean, @tumblreng, and @sfxii

-  460.00 // bar tab       @61local
-  400.00 // food          @61local
-  195.00 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-   64.41 // stickers      @diginate
-   56.76 // cables        @amazon
-   50.00 // venue         @61local
-   28.26 // nametags      @amazon
-   23.99 // KVM switch    @amazon

-  808.78 // donation      @GirlsWhoCode
-  808.78 // donation      @ScriptEdOrg

          // BrooklynJS #6, 2014-04-17T19:00Z at @61Local
          // featuring @donohoe, @dphiffer, @__lucas, @danordille, and @sarajchipps
          // with special musical guest, bathtub jen and the henchmen

+ 1690.00 // ticket sales  @peatix
+ 1500.00 // sponsorship   @spotify, @twilio, and @chartbeat

-  450.00 // bar tab       @61local
-  400.00 // food          @61local
-  200.00 // ticketing     @peatix
-  194.02 // tokens        @CuboNewYork521
-  160.00 // entertainment
-   50.00 // venue         @61local

-  867.99 // donation      @GirlsWhoCode
-  867.99 // donation      @ScriptEdOrg

)
<|endoftext|>


<commit_before>var util = require('util'),
    msgpack = require('msgpack-js'),
    uuid = require('uuid'),
    PROTOCOL_VERSION = 'ZSS:0.0';

var Message = function(sid, verb, sversion){
  var self = this;

  if (!sversion){
    sversion = '*';
  }

  self.identity = null;
  self.protocol = PROTOCOL_VERSION;
  self.type = Message.Type.REQ;
  self.rid = uuid.v1();
  self.address = {
    sid: sid,
    sversion: sversion,
    verb: verb
  };
  self.headers = null;
  self.status = null;
  self.payload = null;

  self.toString = function(){
    var message = "********\nFRAME 0: %s\nFRAME 1: %s\nFRAME 2: %s\nFRAME 3: %s\nFRAME 4: %j\nFRAME 5: %j\nFRAME 6: %s\nFRAME 7: %j\n********";
    return util.format(message, self.identity, self.protocol, self.type, self.rid, self.address, self.headers, self.status, self.payload);
  };

  self.toFrames = function(){
    return Message.toFrames(self);
  };
};

Message.Type = {
  REQ: "REQ",
  REP: "REP"
};

Message.parse = function(frames){
  var msg = new Message();

  if(frames.length === 7) {
    frames.unshift('');
  }

  var identity = String(frames[0]);
  var status = parseInt(frames[6], 10);

  msg.identity = identity === '' ? null : identity;

  var clientParts = !msg.identity ? [null, null] : msg.identity.split('#');
  msg.client = clientParts[0];
  msg.clientId = clientParts[1];

  msg.protocol = String(frames[1]);
  msg.type = String(frames[2]);
  msg.rid = String(frames[3]);
  msg.address = msgpack.decode(frames[4]);

  msg.headers = msgpack.decode(frames[5]);
  msg.transaction = msg.headers['X-Request-Id'] || null;

  msg.status = status ? status : null;
  msg.payload = msgpack.decode(frames[7]);
  return msg;
};

Message.toFrames = function(msg){
  var frames = [
    msg.identity ? msg.identity : '',
    msg.protocol,
    msg.type,
    msg.rid,
    msgpack.encode(msg.address),
    msgpack.encode(msg.headers),
    msg.status,
    msgpack.encode(msg.payload)
  ];
  return frames;
};

module.exports = Message;
<commit_msg>extended ctor to receive identity and headers<commit_after>var util = require('util'),
    msgpack = require('msgpack-js'),
    uuid = require('uuid'),
    PROTOCOL_VERSION = 'ZSS:0.0';

function setClient(msg) {
  var clientParts = !msg.identity ? [null, null] : msg.identity.split('#');
  msg.client = clientParts[0];
  msg.clientId = clientParts[1];
}

function setTransaction(msg) {
  var reqId = msg.headers ? msg.headers['X-Request-Id'] : null;
  msg.transaction = reqId || null;
}

var Message = function(sid, verb, sversion, identity, headers){
  var self = this;

  if (!sversion){
    sversion = '*';
  }

  self.identity = identity || null;
  setClient(self);

  self.protocol = PROTOCOL_VERSION;
  self.type = Message.Type.REQ;
  self.rid = uuid.v1();
  self.address = {
    sid: sid,
    sversion: sversion,
    verb: verb
  };

  self.headers = headers || null;
  setTransaction(self);

  self.status = null;
  self.payload = null;

  self.toString = function(){
    var message = "********\nFRAME 0: %s\nFRAME 1: %s\nFRAME 2: %s\nFRAME 3: %s\nFRAME 4: %j\nFRAME 5: %j\nFRAME 6: %s\nFRAME 7: %j\n********";
    return util.format(message, self.identity, self.protocol, self.type, self.rid, self.address, self.headers, self.status, self.payload);
  };

  self.toFrames = function(){
    return Message.toFrames(self);
  };
};

Message.Type = {
  REQ: "REQ",
  REP: "REP"
};

Message.parse = function(frames){
  var msg = new Message();

  if(frames.length === 7) {
    frames.unshift('');
  }

  var identity = String(frames[0]);
  var status = parseInt(frames[6], 10);

  msg.identity = identity === '' ? null : identity;
  setClient(msg);

  msg.protocol = String(frames[1]);
  msg.type = String(frames[2]);
  msg.rid = String(frames[3]);
  msg.address = msgpack.decode(frames[4]);

  msg.headers = msgpack.decode(frames[5]);
  setTransaction(msg);

  msg.status = status ? status : null;
  msg.payload = msgpack.decode(frames[7]);
  return msg;
};

Message.toFrames = function(msg){
  var frames = [
    msg.identity ? msg.identity : '',
    msg.protocol,
    msg.type,
    msg.rid,
    msgpack.encode(msg.address),
    msgpack.encode(msg.headers),
    msg.status,
    msgpack.encode(msg.payload)
  ];
  return frames;
};

module.exports = Message;
<|endoftext|>


<commit_before>
document.querySelector('.nav-toggle').addEventListener('click', function() {
	var activeClass = 'is-active';
	document.querySelector('.nav-menu').classList.toggle(activeClass);
});

var	tabs = {};
tabs.elements = {};
tabs.func = (function(){

	var exports = {};

	exports.init = function(){

		// Tab Navi aktivieren
		var tabNavigations = document.querySelectorAll('.is-tab-navigation');

		for(i=0; i<tabNavigations.length; i++){
			var tabNavigation = tabNavigations[i];
			var htmltabs = tabNavigation.querySelectorAll('.tab-item');
			htmltabs[0].classList.add('is-active');
			selectTab(htmltabs[0]);

			for(i=0; i<htmltabs.length; i++){
				var htmltab = htmltabs[i];

				htmltab.onclick = function(){ selectTab(this); }
			}

		}
	}

	selectTab = function( ele ){

		var target_id = ele.getAttribute('data-tab');
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content ausblenden
		var items = document.querySelectorAll('.is-tab-content');

		for(i=0; i<items.length; i++){
			var item = items[i];
			item.classList.add('is-hidden');
		}

		// gewählten Content einblenden
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content einblenden
		for(i=0; i<targets.length; i++){
			var target = targets[i];
			target.classList.remove('is-hidden');
		}

		// Aktiven Navipunkt markieren
		var elements = ele.parentElement.querySelectorAll('.tab-item');
		for(i=0; i<elements.length; i++){
			var element = elements[i];
			element.classList.remove('is-active');
		}
		ele.classList.add('is-active');

	}

	return exports;
})();

var	more = {};
more.elements = {};
more.func = (function(){

	var exports = {};

	exports.init = function(){

		var elements = document.querySelectorAll('[data-target]');

		for(i=0; i<elements.length; i++){

			var ele = elements[i];

			var item = document.createElement("i");
			item.classList.add("fa");
			item.classList.add("fa-angle-down");
			item.classList.add("fa-lg");
			item.classList.add("more-button");

			item.onclick = function(){

				if(this.classList.contains("active")){
					var target = this.parentElement.getAttribute("data-target");
					this.classList.remove("active");
					document.getElementById(target).classList.add('is-hidden');

				}else{
					var target = this.parentElement.getAttribute("data-target");
					this.classList.add("active");
					document.getElementById(target).classList.remove('is-hidden');
				}

			}
			ele.appendChild(item);
		}

	}

	return exports;
})();

var	panelTabs = {};
panelTabs.elements = {};
panelTabs.func = (function(){

	var exports = {};

	exports.init = function(){

		// Tab Navi aktivieren
		var tabNavigations = document.querySelectorAll('.panel');

		for(i=0; i<tabNavigations.length; i++){
			var tabNavigation = tabNavigations[i];
			var htmltabs = tabNavigation.querySelectorAll('.panel-block');
			htmltabs[0].classList.add('is-active');
			selectTab(htmltabs[0]);

			for(i=0; i<htmltabs.length; i++){
				var htmltab = htmltabs[i];

				htmltab.onclick = function(){ selectTab(this); }
			}

		}
	}

	selectTab = function( ele ){

		var target_id = ele.getAttribute('data-tab');
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content ausblenden
		var items = document.querySelectorAll('.is-tab-content');

		for(i=0; i<items.length; i++){
			var item = items[i];
			item.classList.add('is-hidden');
		}

		// gewählten Content einblenden
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content einblenden
		for(i=0; i<targets.length; i++){
			var target = targets[i];
			target.classList.remove('is-hidden');
		}

		// Aktiven Navipunkt markieren
		var elements = ele.parentElement.querySelectorAll('.panel-block');
		for(i=0; i<elements.length; i++){
			var element = elements[i];
			element.classList.remove('is-active');
		}
		ele.classList.add('is-active');

	}

	return exports;
})();

var urlParams = new URLSearchParams(window.location.search);
if(!urlParams.has('media')){
	more.func.init();
	tabs.func.init();
	panelTabs.func.init();
}
<commit_msg>panelFucntion fix<commit_after>
document.querySelector('.nav-toggle').addEventListener('click', function() {
	var activeClass = 'is-active';
	document.querySelector('.nav-menu').classList.toggle(activeClass);
});

var	tabs = {};
tabs.elements = {};
tabs.func = (function(){

	var exports = {};

	exports.init = function(){

		// Tab Navi aktivieren
		var tabNavigations = document.querySelectorAll('.is-tab-navigation');

		for(i=0; i<tabNavigations.length; i++){
			var tabNavigation = tabNavigations[i];
			var htmltabs = tabNavigation.querySelectorAll('.tab-item');
			htmltabs[0].classList.add('is-active');
			selectTab(htmltabs[0]);

			for(i=0; i<htmltabs.length; i++){
				var htmltab = htmltabs[i];

				htmltab.onclick = function(){ selectTab(this); }
			}

		}
	}

	selectTab = function( ele ){

		var target_id = ele.getAttribute('data-tab');
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content ausblenden
		var items = document.querySelectorAll('.is-tab-content');

		for(i=0; i<items.length; i++){
			var item = items[i];
			item.classList.add('is-hidden');
		}

		// gewählten Content einblenden
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content einblenden
		for(i=0; i<targets.length; i++){
			var target = targets[i];
			target.classList.remove('is-hidden');
		}

		// Aktiven Navipunkt markieren
		var elements = ele.parentElement.querySelectorAll('.tab-item');
		for(i=0; i<elements.length; i++){
			var element = elements[i];
			element.classList.remove('is-active');
		}
		ele.classList.add('is-active');

	}

	return exports;
})();

var	more = {};
more.elements = {};
more.func = (function(){

	var exports = {};

	exports.init = function(){

		var elements = document.querySelectorAll('[data-target]');

		for(i=0; i<elements.length; i++){

			var ele = elements[i];

			var item = document.createElement("i");
			item.classList.add("fa");
			item.classList.add("fa-angle-down");
			item.classList.add("fa-lg");
			item.classList.add("more-button");

			item.onclick = function(){

				if(this.classList.contains("active")){
					var target = this.parentElement.getAttribute("data-target");
					this.classList.remove("active");
					document.getElementById(target).classList.add('is-hidden');

				}else{
					var target = this.parentElement.getAttribute("data-target");
					this.classList.add("active");
					document.getElementById(target).classList.remove('is-hidden');
				}

			}
			ele.appendChild(item);
		}

	}

	return exports;
})();

var	panelTabs = {};
panelTabs.elements = {};
panelTabs.func = (function(){

	var exports = {};

	exports.init = function(){

		// Tab Navi aktivieren
		var tabNavigations = document.querySelectorAll('.panel');

		for(i=0; i<tabNavigations.length; i++){
			var tabNavigation = tabNavigations[i];
			var htmltabs = tabNavigation.querySelectorAll('.panel-block');
			htmltabs[0].classList.add('is-active');
			selectPanelTab(htmltabs[0]);

			for(i=0; i<htmltabs.length; i++){
				var htmltab = htmltabs[i];

				htmltab.onclick = function(){ selectTab(this); }
			}

		}
	}

	selectPanelTab = function( ele ){

		var target_id = ele.getAttribute('data-tab');
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content ausblenden
		var items = document.querySelectorAll('.is-tab-content');

		for(i=0; i<items.length; i++){
			var item = items[i];
			item.classList.add('is-hidden');
		}

		// gewählten Content einblenden
		var targets = document.querySelectorAll('.is-' + target_id);

		// Content einblenden
		for(i=0; i<targets.length; i++){
			var target = targets[i];
			target.classList.remove('is-hidden');
		}

		// Aktiven Navipunkt markieren
		var elements = ele.parentElement.querySelectorAll('.panel-block');
		for(i=0; i<elements.length; i++){
			var element = elements[i];
			element.classList.remove('is-active');
		}
		ele.classList.add('is-active');

	}

	return exports;
})();

var urlParams = new URLSearchParams(window.location.search);
if(!urlParams.has('media')){
	more.func.init();
	tabs.func.init();
	panelTabs.func.init();
}
<|endoftext|>


<commit_before>'use strict'
var path = require('path')
var Flume = require('flumedb')
var OffsetLog = require('flumelog-offset')
var codec = require('./codec')
var AsyncWrite = require('async-write')
var V = require('ssb-validate')
var timestamp = require('monotonic-timestamp')
var Obv = require('obv')
var ssbKeys = require('ssb-keys')
var box = ssbKeys.box
var u = require('./util')
var isFeed = require('ssb-ref').isFeed

var isArray = Array.isArray
function isFunction (f) { return typeof f === 'function' }

function unbox (data, unboxers, key) {
  var plaintext
  if (data && isString(data.value.content)) {
    for (var i = 0; i < unboxers.length; i++) {
      var unboxer = unboxers[i]

      if (isFunction(unboxer)) {
        plaintext = unboxer(data.value.content, data.value)
      } else {
        if (!key) key = unboxer.key(data.value.content, data.value)
        if (key) plaintext = unboxer.value(data.value.content, key)
      }

      if (plaintext) {
        var msg = {}
        for (var k in data.value) { msg[k] = data.value[k] }

        // set `meta.original.content`
        msg.meta = u.metaBackup(msg, 'content')

        // modify content now that it's saved at `meta.original.content`
        msg.content = plaintext

        // set meta properties for private messages
        msg.meta.private = true
        if (key) { msg.meta.unbox = key.toString('base64') }

        // backward-compatibility with previous property location
        // this property location may be deprecated in favor of `msg.meta`
        msg.cyphertext = msg.meta.original.content
        msg.private = msg.meta.private
        if (key) { msg.unbox = msg.meta.unbox }

        return { key: data.key, value: msg, timestamp: data.timestamp }
      }
    }
  }
  return data
}

/*
## queue (msg, cb)

add a message to the log, buffering the write to make it as fast as
possible, cb when the message is queued.

## append (msg, cb)

write a message, callback once it's definitely written.
*/

function isString (s) {
  return typeof s === 'string'
}

module.exports = function (dirname, keys, opts) {
  var hmacKey = opts && opts.caps && opts.caps.sign

  var mainUnboxer = {
    key: function (content) { return ssbKeys.unboxKey(content, keys) },
    value: function (content, key) { return ssbKeys.unboxBody(content, key) }
  }

  var unboxers = [ mainUnboxer ]

  var log = OffsetLog(path.join(dirname, 'log.offset'), { blockSize: 1024 * 16, codec })

  const unboxerMap = (msg, cb) => cb(null, db.unbox(msg))
  const maps = [ unboxerMap ]
  const chainMaps = (val, cb) => {
    // assumes `maps.length >= 1`
    if (maps.length === 1) {
      maps[0](val, cb)
    } else {
      let idx = -1 // haven't entered the chain yet
      const next = (err, val) => {
        idx += 1
        if (err || idx === maps.length) {
          cb(err, val)
        } else {
          maps[idx](val, next)
        }
      }
      next(null, val)
    }
  }

  // NOTE: must use db.ready.set(true) at when migration is complete
  // false says the database is not ready yet!
  var db = Flume(log, false, chainMaps)
    .use('last', require('./indexes/last')())

  var state = V.initial()
  var ready = false
  var waiting = []
  var flush = []

  var append = db.rawAppend = db.append
  db.post = Obv()
  var queue = AsyncWrite(function (_, cb) {
    var batch = state.queue
    state.queue = []
    append(batch, function (err, v) {
      batch.forEach(function (data) {
        db.post.set(u.originalData(data))
      })
      cb(err, v)
    })
  }, function reduce (_, msg) {
    return V.append(state, hmacKey, msg)
  }, function (_state) {
    return state.queue.length > 1000
  }, function isEmpty (_state) {
    return !state.queue.length
  }, 100)

  queue.onDrain = function () {
    if (state.queue.length === 0) {
      var l = flush.length
      for (var i = 0; i < l; ++i) { flush[i]() }
      flush = flush.slice(l)
    }
  }

  db.last.get(function (err, last) {
    if (err) throw err

    // copy to so we avoid weirdness, because this object
    // tracks the state coming in to the database.
    for (var k in last) {
      state.feeds[k] = {
        id: last[k].id,
        timestamp: last[k].ts || last[k].timestamp,
        sequence: last[k].sequence,
        queue: []
      }
    }
    ready = true

    var l = waiting.length
    for (var i = 0; i < l; ++i) { waiting[i]() }
    waiting = waiting.slice(l)
  })

  function wait (fn) {
    return function (value, cb) {
      if (ready) fn(value, cb)
      else {
        waiting.push(function () {
          fn(value, cb)
        })
      }
    }
  }

  db.queue = wait(function (msg, cb) {
    queue(msg, function (err) {
      var data = state.queue[state.queue.length - 1]
      if (err) cb(err)
      else cb(null, data)
    })
  })

  db.append = wait(function (opts, cb) {
    try {
      var content = opts.content
      var recps = opts.content.recps
      if (recps) {
        const isNonEmptyArrayOfFeeds = isArray(recps) && recps.every(isFeed) && recps.length > 0
        if (isFeed(recps) || isNonEmptyArrayOfFeeds) {
          recps = opts.content.recps = [].concat(recps) // force to array
          content = opts.content = box(opts.content, recps)
        } else {
          const errMsg = 'private message recipients must be valid, was:' + JSON.stringify(recps)
          throw new Error(errMsg)
        }
      }

      var msg = V.create(
        state.feeds[opts.keys.id],
        opts.keys, opts.hmacKey || hmacKey,
        content,
        timestamp()
      )
    } catch (err) {
      cb(err)
      return
    }

    queue(msg, function (err) {
      if (err) return cb(err)
      var data = state.queue[state.queue.length - 1]
      flush.push(function () {
        cb(null, data)
      })
    })
  })

  db.buffer = function () {
    return queue.buffer
  }

  db.flush = function (cb) {
    // maybe need to check if there is anything currently writing?
    const isEmptyInactiveQueue = !queue.buffer.queue.length && !queue.writing
    if (!queue.buffer || isEmptyInactiveQueue) cb()
    else flush.push(cb)
  }

  db.addUnboxer = function (unboxer) {
    unboxers.push(unboxer)
  }

  db.unbox = function (data, key) {
    return unbox(data, unboxers, key)
  }
  db.addMap = function (fn) {
    maps.push(fn)
  }

  return db
}
<commit_msg>pass value to unbox value (so that previous is accessable, for instance)<commit_after>'use strict'
var path = require('path')
var Flume = require('flumedb')
var OffsetLog = require('flumelog-offset')
var codec = require('./codec')
var AsyncWrite = require('async-write')
var V = require('ssb-validate')
var timestamp = require('monotonic-timestamp')
var Obv = require('obv')
var ssbKeys = require('ssb-keys')
var box = ssbKeys.box
var u = require('./util')
var isFeed = require('ssb-ref').isFeed

var isArray = Array.isArray
function isFunction (f) { return typeof f === 'function' }

function unbox (data, unboxers, key) {
  var plaintext
  if (data && isString(data.value.content)) {
    for (var i = 0; i < unboxers.length; i++) {
      var unboxer = unboxers[i]
      if (isFunction(unboxer)) {
        plaintext = unboxer(data.value.content, data.value)
      } else {
        if (!key) key = unboxer.key(data.value.content, data.value)
        if (key) plaintext = unboxer.value(data.value.content, key, data.value)
      }

      if (plaintext) {
        var msg = {}
        for (var k in data.value) { msg[k] = data.value[k] }

        // set `meta.original.content`
        msg.meta = u.metaBackup(msg, 'content')

        // modify content now that it's saved at `meta.original.content`
        msg.content = plaintext

        // set meta properties for private messages
        msg.meta.private = true
        if (key) { msg.meta.unbox = key.toString('base64') }

        // backward-compatibility with previous property location
        // this property location may be deprecated in favor of `msg.meta`
        msg.cyphertext = msg.meta.original.content
        msg.private = msg.meta.private
        if (key) { msg.unbox = msg.meta.unbox }

        return { key: data.key, value: msg, timestamp: data.timestamp }
      }
    }
  }
  return data
}

/*
## queue (msg, cb)

add a message to the log, buffering the write to make it as fast as
possible, cb when the message is queued.

## append (msg, cb)

write a message, callback once it's definitely written.
*/

function isString (s) {
  return typeof s === 'string'
}

module.exports = function (dirname, keys, opts) {
  var hmacKey = opts && opts.caps && opts.caps.sign

  var mainUnboxer = {
    key: function (content) { return ssbKeys.unboxKey(content, keys) },
    value: function (content, key) { return ssbKeys.unboxBody(content, key) }
  }

  var unboxers = [ mainUnboxer ]

  var log = OffsetLog(path.join(dirname, 'log.offset'), { blockSize: 1024 * 16, codec })

  const unboxerMap = (msg, cb) => cb(null, db.unbox(msg))
  const maps = [ unboxerMap ]
  const chainMaps = (val, cb) => {
    // assumes `maps.length >= 1`
    if (maps.length === 1) {
      maps[0](val, cb)
    } else {
      let idx = -1 // haven't entered the chain yet
      const next = (err, val) => {
        idx += 1
        if (err || idx === maps.length) {
          cb(err, val)
        } else {
          maps[idx](val, next)
        }
      }
      next(null, val)
    }
  }

  // NOTE: must use db.ready.set(true) at when migration is complete
  // false says the database is not ready yet!
  var db = Flume(log, false, chainMaps)
    .use('last', require('./indexes/last')())

  var state = V.initial()
  var ready = false
  var waiting = []
  var flush = []

  var append = db.rawAppend = db.append
  db.post = Obv()
  var queue = AsyncWrite(function (_, cb) {
    var batch = state.queue
    state.queue = []
    append(batch, function (err, v) {
      batch.forEach(function (data) {
        db.post.set(u.originalData(data))
      })
      cb(err, v)
    })
  }, function reduce (_, msg) {
    return V.append(state, hmacKey, msg)
  }, function (_state) {
    return state.queue.length > 1000
  }, function isEmpty (_state) {
    return !state.queue.length
  }, 100)

  queue.onDrain = function () {
    if (state.queue.length === 0) {
      var l = flush.length
      for (var i = 0; i < l; ++i) { flush[i]() }
      flush = flush.slice(l)
    }
  }

  db.last.get(function (err, last) {
    if (err) throw err

    // copy to so we avoid weirdness, because this object
    // tracks the state coming in to the database.
    for (var k in last) {
      state.feeds[k] = {
        id: last[k].id,
        timestamp: last[k].ts || last[k].timestamp,
        sequence: last[k].sequence,
        queue: []
      }
    }
    ready = true

    var l = waiting.length
    for (var i = 0; i < l; ++i) { waiting[i]() }
    waiting = waiting.slice(l)
  })

  function wait (fn) {
    return function (value, cb) {
      if (ready) fn(value, cb)
      else {
        waiting.push(function () {
          fn(value, cb)
        })
      }
    }
  }

  db.queue = wait(function (msg, cb) {
    queue(msg, function (err) {
      var data = state.queue[state.queue.length - 1]
      if (err) cb(err)
      else cb(null, data)
    })
  })

  db.append = wait(function (opts, cb) {
    try {
      var content = opts.content
      var recps = opts.content.recps
      if (recps) {
        const isNonEmptyArrayOfFeeds = isArray(recps) && recps.every(isFeed) && recps.length > 0
        if (isFeed(recps) || isNonEmptyArrayOfFeeds) {
          recps = opts.content.recps = [].concat(recps) // force to array
          content = opts.content = box(opts.content, recps)
        } else {
          const errMsg = 'private message recipients must be valid, was:' + JSON.stringify(recps)
          throw new Error(errMsg)
        }
      }

      var msg = V.create(
        state.feeds[opts.keys.id],
        opts.keys, opts.hmacKey || hmacKey,
        content,
        timestamp()
      )
    } catch (err) {
      cb(err)
      return
    }

    queue(msg, function (err) {
      if (err) return cb(err)
      var data = state.queue[state.queue.length - 1]
      flush.push(function () {
        cb(null, data)
      })
    })
  })

  db.buffer = function () {
    return queue.buffer
  }

  db.flush = function (cb) {
    // maybe need to check if there is anything currently writing?
    const isEmptyInactiveQueue = !queue.buffer.queue.length && !queue.writing
    if (!queue.buffer || isEmptyInactiveQueue) cb()
    else flush.push(cb)
  }

  db.addUnboxer = function (unboxer) {
    unboxers.push(unboxer)
  }

  db.unbox = function (data, key) {
    return unbox(data, unboxers, key)
  }
  db.addMap = function (fn) {
    maps.push(fn)
  }

  return db
}
<|endoftext|>


<commit_before>var client = new Messaging.Client("MQTT BROKER", 80, "NAME_" + parseInt(Math.random() * 100, 10));

//"arduino_" + parseInt(Math.random() * 100, 10)
//Gets  called if the websocket/mqtt connection gets disconnected for any reason
client.onConnectionLost = function (responseObject) {
    //Depending on your scenario you could implement a reconnect logic here

};
//Gets called whenever you receive a message for your subscriptions
function connectRoom(site_publish, callback) {
    client.onMessageArrived = function (message) {
       // Your CALL BACK MESSAGE - FUNCTION
    };
}

//Connect Options
var options = {
    timeout: 3,

    onSuccess: function () {
        door = true;
    }
    ,
    //Gets Called if the connection could not be established
    onFailure: function (message) {
    }
};
//Creates a new Messaging.Message Object and sends it to the HiveMQ MQTT Broker
var publish = function (payload, topic, qos) {
    //Send your message (also possible to serialize it as JSON or protobuf or just use a string, no limitations)
    var message = new Messaging.Message(payload);
    message.isRetained = false;
    message.destinationName = topic;
    message.qos = qos;
    client.send(message);
}
<commit_msg>Update message.js<commit_after>var client = new Messaging.Client("MQTT BROKER", 80, "NAME_" + parseInt(Math.random() * 100, 10));

//"arduino_" + parseInt(Math.random() * 100, 10)
//Gets  called if the websocket/mqtt connection gets disconnected for any reason
client.onConnectionLost = function (responseObject) {
    //Depending on your scenario you could implement a reconnect logic here

};
//Gets called whenever you receive a message for your subscriptions
function connectRoom(site_publish, callback) {
    client.onMessageArrived = function (message) {
       // Your CALL BACK MESSAGE
    };
}

//Connect Options
var options = {
    timeout: 3,

    onSuccess: function () {
        door = true;
    }
    ,
    //Gets Called if the connection could not be established
    onFailure: function (message) {
    }
};
//Creates a new Messaging.Message Object and sends it to the HiveMQ MQTT Broker
var publish = function (payload, topic, qos) {
    //Send your message (also possible to serialize it as JSON or protobuf or just use a string, no limitations)
    var message = new Messaging.Message(payload);
    message.isRetained = false;
    message.destinationName = topic;
    message.qos = qos;
    client.send(message);
}
<|endoftext|>


<commit_before>$(document).ready(function(){
	$db="relax-o-notes";
	$url="http://localhost:5984/"+$db+"/_design/app/";
	$flag=0;

	var p=$("#page_name").attr("data-page");

	if(p=="index.html"){
		$("#upload_file_btn").live("click", function(){
		var d=new Date();
		d=d.toISOString();
		var tags=$("#upload_message").val().split(" ");
		var act_tags="", k=0;
		for(var j=0;j<tags.length;j++){
			if(tags[j].indexOf('#') == 0){
				act_tags=act_tags+" "+tags[j];
				act_tags=act_tags.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '');
				k++;
			}
		}
		act_tags=act_tags.substring(1,act_tags.length);
		var doc={
			"uploaded_by": $("#uploaded_by").val(),
			"gravatar_url": "http://api.twitter.com/1/users/profile_image/"+$("#uploaded_by").val(),
			"uploader_msg": $("#upload_message").val(),
			"created_at": d,
			"tags": act_tags.split(" ")
		};
		$.couch.db($db).saveDoc(doc,{
			success: function(data){
				var id=data.id;
				var stat=data.ok;
				if(stat){
					$("#uploadModal").modal('hide');
				}
			},
			error: function(data){
				console.log(data);
			}
		});
		return false;
	});

		$.couch.db($db).view("app/notes/",{
			success: function(data){
				$("#all_notes").html('');
				var val;
				for(var i=0;i<data.total_rows;i++){
					val=data.rows[i].value;
					$("#all_notes").append("
"+val.user+"
"+val.uploader_msg+"

");
					$(".date_time-block").timeago();
				}
				$("#all_notes").hide().fadeIn(500);
			},
			error: function(data){
				console.log(data);
			}
		});

		$.couch.db($db).view("app/hashtags/",{
		success: function(data){
			$("#hashtags").html('');
			var val;
			for(var i=0;i<data.total_rows;i++){
				val=data.rows[i].value;
				for(var j=0;j<val.length;j++)
					$("#hashtags").append(""+val[j]+"  ");
			}
			$("#hashtags").hide().fadeIn(500);
		},
		error: function(data){
			console.log(data);
		}
	});

	}

	else if(p=="discussion.html"){

		$("#discuss_btn").live("click",function(){
		var th=$.trim($("#uploaded_by").val());
		var dt=$.trim($("#discuss_title").val());
		var dm=$.trim($("#discuss_message").val());
		if(th=='' || dt=='' || dm==''){
			if(th==''){
				$("#uploaded_by").focus();
			}
			else if(dt==''){
				$("#discuss_title").focus();
			}
			else if(dm==''){
				$("#discuss_message").focus();
			}
			else{

			}
		}
		else{
			var d=new Date();
			d=d.toISOString();
			var uid=$.couch.newUUID();
			uid="discuss_"+uid;
			var doc={
				"_id": uid,
				"title": dt,
				"author": th,
				"content": dm ,
				"date": d,
				"author_pic": "http://api.twitter.com/1/users/profile_image/"+th,
				"type": "discussion"
			};
			$.couch.db($db).saveDoc(doc,{
			success: function(data){
				var id=data.id;
				var stat=data.ok;
				if(stat){
					$("#discussModal").modal('hide');
				}
			},
			error: function(data){
				console.log(data);
			}
		});
		}
		return false;
	});

		$.couch.db($db).view("app/discuss/",{
			success: function(data){
				console.log(data);
				$("#all_discussions").html('');
				var val;
				for(var i=0;i<data.total_rows;i++){
					val=data.rows[i].value;
					$("#all_discussions").append("
"+val.title+"
"+val.content+"
View Comments

");
					$(".date_time-block").timeago();
					$("#t"+data.rows[i].id).tooltip('hide');
				}
				$("#all_discussions").hide().fadeIn(500);
			},
			error: function(data){
				console.log(data);
			}
		});
	}

	else{

	}

	$.couch.db($db).changes().onChange(function(data){
		var id=data.results[0].id;
		var sub=id.substring(0,7);
		if(id=="_design/app"){

		}
		else if(sub=="discuss"){
			$.couch.db($db).openDoc(id,{
			success: function(obj){
				$("#all_discussions").prepend("
"+obj.title+"
"+obj.content+"
Comments(0)

");
					$(".date_time-block").timeago();
					$("#t"+id).tooltip('hide');
			},
			error: function(data2){
				if(data2==404){
					$("#"+id).fadeOut(500);
				}
			}
		});
		}
		else if(sub=="comment"){
			var change_id;
			$.couch.db($db).openDoc(id,{
				success: function(data){
					$("#comments_main").prepend("
"+data.author+"
"+data.comment+"

");
					$(".date_time-block").timeago();
					$.couch.db($db).view("app/get_discussid",{
						success: function(data2){
							$("#notify").prepend("New Comment

").hide().fadeIn(500);
						},
						error: function(err2){
							console.log(err2);
						},
						key: id
					});
				},
				error: function(err){
					console.log(err);
				}
			});
		}
		else{
		$.couch.db($db).openDoc(id,{
			success: function(obj){
				$("#all_notes").prepend("
"+obj.uploaded_by+"
"+obj.uploader_msg+"

").hide().fadeIn(500);
				$(".date_time-block").timeago();
			},
			error: function(data2){
				console.log("Data is:"+data2);
				if(data2==404){
					$("#"+id).fadeOut(500);
				}
			}
		});
	 }
	});

	$(".discuss_comments").live("click",function(){
		var id=$(this).attr("data-id");
		var discuss_title=$(this).attr("data-discuss_title");
		id=id.substring(2);
		$("#comment_on_id").val(id);
		$.couch.db($db).view("app/comments/",{
			success: function(data){
				for(var i=0;i<data.rows.length;i++){
					$("#comments_main").prepend("
"+data.rows[i].value.author+"
"+data.rows[i].value.comment+"

");
					$(".date_time-block").timeago();
				}
			},
			error: function(err){
				console.log(err);
			},
			key: id
		});
		$("#comments_main").html('').show();
		$("#comments_title").html("Comments for: "+discuss_title+"   (Add Comment)").hide().show();
		$("#comments_main").show();
	});

	$("#toggle_comment_box").live("click",function(){
		$("#my_comment_box").slideToggle(500);
	});

	$("#add_comment").live("click",function(){
		var did=$("#comment_on_id").val();
		var d=new Date();
		d=d.toISOString();
		var uid=$.couch.newUUID();
		uid="comment_"+uid;
		var doc={
			"_id": uid,
			"type": "comment",
			"author": $("#comment_by").val(),
			"author_pic": "http://api.twitter.com/1/users/profile_image/"+$("#comment_by").val(),
			"comment": $("#comment_msg").val(),
			"date": d,
			"discussion": did
		}
		$.couch.db($db).saveDoc(doc,{
			success: function(data){
				console.log(data);
			},
			error: function(err){
				console.log(err);
			}
		});
		$("#my_comment_box").slideUp(500);
	});

	$(".discuss_main_title").live("click",function(){
		var id=$(this).attr('href');
		id=id.substring(1);
		var com_id=$(this).attr('data-scroll');
		get_all_comments(id,com_id);
		return false;
	});

	function get_all_comments(id,com_id){
		$.couch.db($db).view("app/single_discuss",{
			success: function(data){
				$("#toggle-main").html("

"+data.rows[0].value.title+"
"+data.rows[0].value.content+"

");
				$(".date_time-block").timeago();
				$("#t"+data.rows[0].id).tooltip('hide');
				$.couch.db($db).view("app/comments",{
					success: function(data2){
						$("#comments_header").html('
Comments:
');
						for(var i=0;i<data2.rows.length;i++){
					$("#my_comments").append("

"+data2.rows[i].value.author+"
"+data2.rows[i].value.comment+"

");
					$(".date_time-block").timeago();
				}
				if(com_id!=''){
					$('html, body').animate({ scrollTop: $("#"+com_id).offset().top -60 }, 'slow');
					$("#"+com_id).css("background","#FCF8E3");
				}
					},
					error: function(err2){
						console.log(err);
					},
					key: id
				});
				$("#toggle-main").hide().fadeIn(500);
				$("#comments_header").hide().fadeIn(500);
				$("#all_comments").hide().fadeIn(500);
			},
			error: function(err){
				console.log(err);
			},
			key: id
		});
	}

});
<commit_msg>changed href from #<discuss_id> to #<commit_after>$(document).ready(function(){
	$db="relax-o-notes";
	$url="http://localhost:5984/"+$db+"/_design/app/";
	$flag=0;

	var p=$("#page_name").attr("data-page");

	if(p=="index.html"){
		$("#upload_file_btn").live("click", function(){
		var d=new Date();
		d=d.toISOString();
		var tags=$("#upload_message").val().split(" ");
		var act_tags="", k=0;
		for(var j=0;j<tags.length;j++){
			if(tags[j].indexOf('#') == 0){
				act_tags=act_tags+" "+tags[j];
				act_tags=act_tags.replace(/[`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, '');
				k++;
			}
		}
		act_tags=act_tags.substring(1,act_tags.length);
		var doc={
			"uploaded_by": $("#uploaded_by").val(),
			"gravatar_url": "http://api.twitter.com/1/users/profile_image/"+$("#uploaded_by").val(),
			"uploader_msg": $("#upload_message").val(),
			"created_at": d,
			"tags": act_tags.split(" ")
		};
		$.couch.db($db).saveDoc(doc,{
			success: function(data){
				var id=data.id;
				var stat=data.ok;
				if(stat){
					$("#uploadModal").modal('hide');
				}
			},
			error: function(data){
				console.log(data);
			}
		});
		return false;
	});

		$.couch.db($db).view("app/notes/",{
			success: function(data){
				$("#all_notes").html('');
				var val;
				for(var i=0;i<data.total_rows;i++){
					val=data.rows[i].value;
					$("#all_notes").append("
"+val.user+"
"+val.uploader_msg+"

");
					$(".date_time-block").timeago();
				}
				$("#all_notes").hide().fadeIn(500);
			},
			error: function(data){
				console.log(data);
			}
		});

		$.couch.db($db).view("app/hashtags/",{
		success: function(data){
			$("#hashtags").html('');
			var val;
			for(var i=0;i<data.total_rows;i++){
				val=data.rows[i].value;
				for(var j=0;j<val.length;j++)
					$("#hashtags").append(""+val[j]+"  ");
			}
			$("#hashtags").hide().fadeIn(500);
		},
		error: function(data){
			console.log(data);
		}
	});

	}

	else if(p=="discussion.html"){

		$("#discuss_btn").live("click",function(){
		var th=$.trim($("#uploaded_by").val());
		var dt=$.trim($("#discuss_title").val());
		var dm=$.trim($("#discuss_message").val());
		if(th=='' || dt=='' || dm==''){
			if(th==''){
				$("#uploaded_by").focus();
			}
			else if(dt==''){
				$("#discuss_title").focus();
			}
			else if(dm==''){
				$("#discuss_message").focus();
			}
			else{

			}
		}
		else{
			var d=new Date();
			d=d.toISOString();
			var uid=$.couch.newUUID();
			uid="discuss_"+uid;
			var doc={
				"_id": uid,
				"title": dt,
				"author": th,
				"content": dm ,
				"date": d,
				"author_pic": "http://api.twitter.com/1/users/profile_image/"+th,
				"type": "discussion"
			};
			$.couch.db($db).saveDoc(doc,{
			success: function(data){
				var id=data.id;
				var stat=data.ok;
				if(stat){
					$("#discussModal").modal('hide');
				}
			},
			error: function(data){
				console.log(data);
			}
		});
		}
		return false;
	});

		$.couch.db($db).view("app/discuss/",{
			success: function(data){
				console.log(data);
				$("#all_discussions").html('');
				var val;
				for(var i=0;i<data.total_rows;i++){
					val=data.rows[i].value;
					$("#all_discussions").append("
"+val.title+"
"+val.content+"
View Comments

");
					$(".date_time-block").timeago();
					$("#t"+data.rows[i].id).tooltip('hide');
				}
				$("#all_discussions").hide().fadeIn(500);
			},
			error: function(data){
				console.log(data);
			}
		});
	}

	else{

	}

	$.couch.db($db).changes().onChange(function(data){
		var id=data.results[0].id;
		var sub=id.substring(0,7);
		if(id=="_design/app"){

		}
		else if(sub=="discuss"){
			$.couch.db($db).openDoc(id,{
			success: function(obj){
				$("#all_discussions").prepend("
"+obj.title+"
"+obj.content+"
Comments(0)

");
					$(".date_time-block").timeago();
					$("#t"+id).tooltip('hide');
			},
			error: function(data2){
				if(data2==404){
					$("#"+id).fadeOut(500);
				}
			}
		});
		}
		else if(sub=="comment"){
			var change_id;
			$.couch.db($db).openDoc(id,{
				success: function(data){
					$("#comments_main").prepend("
"+data.author+"
"+data.comment+"

");
					$(".date_time-block").timeago();
					$.couch.db($db).view("app/get_discussid",{
						success: function(data2){
							$("#notify").prepend("New Comment

").hide().fadeIn(500);
						},
						error: function(err2){
							console.log(err2);
						},
						key: id
					});
				},
				error: function(err){
					console.log(err);
				}
			});
		}
		else{
		$.couch.db($db).openDoc(id,{
			success: function(obj){
				$("#all_notes").prepend("
"+obj.uploaded_by+"
"+obj.uploader_msg+"

").hide().fadeIn(500);
				$(".date_time-block").timeago();
			},
			error: function(data2){
				console.log("Data is:"+data2);
				if(data2==404){
					$("#"+id).fadeOut(500);
				}
			}
		});
	 }
	});

	$(".discuss_comments").live("click",function(){
		var id=$(this).attr("data-id");
		var discuss_title=$(this).attr("data-discuss_title");
		id=id.substring(2);
		$("#comment_on_id").val(id);
		$.couch.db($db).view("app/comments/",{
			success: function(data){
				for(var i=0;i<data.rows.length;i++){
					$("#comments_main").prepend("
"+data.rows[i].value.author+"
"+data.rows[i].value.comment+"

");
					$(".date_time-block").timeago();
				}
			},
			error: function(err){
				console.log(err);
			},
			key: id
		});
		$("#comments_main").html('').show();
		$("#comments_title").html("Comments for: "+discuss_title+"   (Add Comment)").hide().show();
		$("#comments_main").show();
	});

	$("#toggle_comment_box").live("click",function(){
		$("#my_comment_box").slideToggle(500);
	});

	$("#add_comment").live("click",function(){
		var did=$("#comment_on_id").val();
		var d=new Date();
		d=d.toISOString();
		var uid=$.couch.newUUID();
		uid="comment_"+uid;
		var doc={
			"_id": uid,
			"type": "comment",
			"author": $("#comment_by").val(),
			"author_pic": "http://api.twitter.com/1/users/profile_image/"+$("#comment_by").val(),
			"comment": $("#comment_msg").val(),
			"date": d,
			"discussion": did
		}
		$.couch.db($db).saveDoc(doc,{
			success: function(data){
				console.log(data);
			},
			error: function(err){
				console.log(err);
			}
		});
		$("#my_comment_box").slideUp(500);
	});

	$(".discuss_main_title").live("click",function(){
		var id=$(this).attr('href');
		id=id.substring(1);
		var com_id=$(this).attr('data-scroll');
		get_all_comments(id,com_id);
		return false;
	});

	function get_all_comments(id,com_id){
		$.couch.db($db).view("app/single_discuss",{
			success: function(data){
				$("#toggle-main").html("

"+data.rows[0].value.title+"
"+data.rows[0].value.content+"

");
				$(".date_time-block").timeago();
				$("#t"+data.rows[0].id).tooltip('hide');
				$.couch.db($db).view("app/comments",{
					success: function(data2){
						$("#comments_header").html('
Comments:
');
						for(var i=0;i<data2.rows.length;i++){
					$("#my_comments").append("

"+data2.rows[i].value.author+"
"+data2.rows[i].value.comment+"

");
					$(".date_time-block").timeago();
				}
				if(com_id!=''){
					$('html, body').animate({ scrollTop: $("#"+com_id).offset().top -60 }, 'slow');
					$("#"+com_id).css("background","#FCF8E3");
				}
					},
					error: function(err2){
						console.log(err);
					},
					key: id
				});
				$("#toggle-main").hide().fadeIn(500);
				$("#comments_header").hide().fadeIn(500);
				$("#all_comments").hide().fadeIn(500);
			},
			error: function(err){
				console.log(err);
			},
			key: id
		});
	}

});
<|endoftext|>


<commit_before>require('./core');
require('./controller');
require('./templates');
require('./views');

IRC.MessagesView.appendTo('#messages');
IRC.DaysView.appendTo('#days');

IRC.set('daysController', IRC.DaysController.create());
IRC.set('messagesController', IRC.MessagesController.create());

IRC.set('dataSource', Ember.Object.create({

    loadDay: function(day) {
        IRC.messagesController.clear();
        IRC.messagesController.set('loading', true);
        var from = day || IRC.createDateTime();
        var to = from.advance({
            day: 1
        });
        IRC.messagesController.set('date', from);
        $.couch.db('irc').view('irc/messages', {
            success: function(data) {
                IRC.messagesController.set('loading', false);
                if (data && data.rows && data.rows.length > 0) {
                    data.rows.forEach(function(row) {
                        IRC.messagesController.addMessage(row.doc);
                    });
                }
            },
            include_docs: true,
            reduce: false,
            startkey: IRC.getDateArray(from, 'year', 'month', 'day'),
            endkey: IRC.getDateArray(to, 'year', 'month', 'day')
        });
    }

}));
IRC.dataSource.loadDay(IRC.createDateTime().adjust({
    hour: 0,
    timezone: 0
}));

$.couch.db('irc').view('irc/messages', {
    success: function(data) {
        if (data && data.rows && data.rows.length > 0) {
            IRC.daysController.set('loading', false);
            data.rows.forEach(function(doc) {
                var key = doc.key;
                var date = Ember.DateTime.create().adjust({
                    year: key[0],
                    month: key[1],
                    day: key[2],
                    hour: 0,
                    timezone: 0
                });
                IRC.daysController.addDay({
                    date: date,
                    count: doc.value
                });
            });
        }
    },
    group_level: 3,
    descending: true
});<commit_msg>add setting of loading property after the data has been added to the controller<commit_after>require('./core');
require('./controller');
require('./templates');
require('./views');

IRC.MessagesView.appendTo('#messages');
IRC.DaysView.appendTo('#days');

IRC.set('daysController', IRC.DaysController.create());
IRC.set('messagesController', IRC.MessagesController.create());

IRC.set('dataSource', Ember.Object.create({

    loadDay: function(day) {
        IRC.messagesController.clear();
        IRC.messagesController.set('loading', true);
        var from = day || IRC.createDateTime();
        var to = from.advance({
            day: 1
        });
        IRC.messagesController.set('date', from);
        $.couch.db('irc').view('irc/messages', {
            success: function(data) {
                if (data && data.rows && data.rows.length > 0) {
                    data.rows.forEach(function(row) {
                        IRC.messagesController.addMessage(row.doc);
                    });
                }
                IRC.messagesController.set('loading', false);
            },
            include_docs: true,
            reduce: false,
            startkey: IRC.getDateArray(from, 'year', 'month', 'day'),
            endkey: IRC.getDateArray(to, 'year', 'month', 'day')
        });
    }

}));
IRC.dataSource.loadDay(IRC.createDateTime().adjust({
    hour: 0,
    timezone: 0
}));

$.couch.db('irc').view('irc/messages', {
    success: function(data) {
        if (data && data.rows && data.rows.length > 0) {
            data.rows.forEach(function(doc) {
                var key = doc.key;
                var date = Ember.DateTime.create().adjust({
                    year: key[0],
                    month: key[1],
                    day: key[2],
                    hour: 0,
                    timezone: 0
                });
                IRC.daysController.addDay({
                    date: date,
                    count: doc.value
                });
            });
        }
        IRC.daysController.set('loading', false);
    },
    group_level: 3,
    descending: true
});<|endoftext|>


<commit_before>import { test, moduleForComponent } from 'ember-qunit';
import Ember from 'ember';
import { openDatepicker } from 'ember-pikaday/helpers/pikaday';

moduleForComponent('pikaday-input', 'PikadayInputComponent');

test('is an input tag', function(assert) {
  assert.equal('INPUT', this.$().prop('tagName'));
});

test('the input tag has the readonly attribute if it has been set on the component', function(assert) {
  var component = this.subject();
  component.set('readonly', true);

  assert.ok(this.$().is('[readonly]'));
});

test('clicking the input opens the pikaday dialog', function(assert) {
  var $input = this.render();

  assert.ok($('.pika-single').hasClass('is-hidden'));
  openDatepicker($input);
  assert.ok(!$('.pika-single').hasClass('is-hidden'));
});

test('selecting a date should update the value attribute', function(assert) {
  var component = this.subject();
  var $input = this.render();
  var interactor = openDatepicker($input);

  interactor.selectDate(new Date(2013, 3, 28));

  var date = this.subject().get('value');

  assert.equal(date.getFullYear(), 2013);
  assert.equal(date.getMonth(), 3);
  assert.equal(date.getDate(), 28);
});

test('setting the value attribute should select the correct date', function(assert) {
  var $input = this.render();

  this.subject().set('value', new Date(2010, 7, 10));
  var interactor = openDatepicker($input);

  assert.equal(interactor.selectedYear(), 2010);
  assert.equal(interactor.selectedMonth(), 7);
  assert.equal(interactor.selectedDay(), 10);
});

test('DD.MM.YYYY should be the default format for the input', function(assert) {
  var $input = this.render();
  this.subject().set('value', new Date(2010, 7, 10));

  assert.equal($input.val(), '10.08.2010');
});

test('format of the input is changeable', function(assert) {
  this.subject().set('format', 'YYYY.DD.MM');
  var $input = this.render();
  this.subject().set('value', new Date(2010, 7, 10));

  assert.equal($input.val(), '2010.10.08');
});

test('default i18n configuration of Pikaday can be changed', function(assert) {
  var component = this.subject({
    i18n: {
      previousMonth: 'Vorheriger Monat',
      nextMonth: 'Nächster Monat',
      months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
      weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
      weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
    }
  });

  var $input = this.render();

  component.set('value', new Date(2014, 2, 10));
  openDatepicker($input);

  assert.equal($('.pika-select-month option:selected').text(), 'März');
});
<commit_msg>test for setting UTC time<commit_after>import { test, moduleForComponent } from 'ember-qunit';
import Ember from 'ember';
import { openDatepicker } from 'ember-pikaday/helpers/pikaday';

moduleForComponent('pikaday-input', 'PikadayInputComponent');

test('is an input tag', function(assert) {
  assert.equal('INPUT', this.$().prop('tagName'));
});

test('the input tag has the readonly attribute if it has been set on the component', function(assert) {
  var component = this.subject();
  component.set('readonly', true);

  assert.ok(this.$().is('[readonly]'));
});

test('clicking the input opens the pikaday dialog', function(assert) {
  var $input = this.render();

  assert.ok($('.pika-single').hasClass('is-hidden'));
  openDatepicker($input);
  assert.ok(!$('.pika-single').hasClass('is-hidden'));
});

test('selecting a date should update the value attribute', function(assert) {
  var component = this.subject();
  var $input = this.render();
  var interactor = openDatepicker($input);

  interactor.selectDate(new Date(2013, 3, 28));

  var date = this.subject().get('value');

  assert.equal(date.getFullYear(), 2013);
  assert.equal(date.getMonth(), 3);
  assert.equal(date.getDate(), 28);
});

test('setting the value attribute should select the correct date', function(assert) {
  var $input = this.render();

  this.subject().set('value', new Date(2010, 7, 10));
  var interactor = openDatepicker($input);

  assert.equal(interactor.selectedYear(), 2010);
  assert.equal(interactor.selectedMonth(), 7);
  assert.equal(interactor.selectedDay(), 10);
});

test('DD.MM.YYYY should be the default format for the input', function(assert) {
  var $input = this.render();
  this.subject().set('value', new Date(2010, 7, 10));

  assert.equal($input.val(), '10.08.2010');
});

test('format of the input is changeable', function(assert) {
  this.subject().set('format', 'YYYY.DD.MM');
  var $input = this.render();
  this.subject().set('value', new Date(2010, 7, 10));

  assert.equal($input.val(), '2010.10.08');
});

test('default i18n configuration of Pikaday can be changed', function(assert) {
  var component = this.subject({
    i18n: {
      previousMonth: 'Vorheriger Monat',
      nextMonth: 'Nächster Monat',
      months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],
      weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
      weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']
    }
  });

  var $input = this.render();

  component.set('value', new Date(2014, 2, 10));
  openDatepicker($input);

  assert.equal($('.pika-select-month option:selected').text(), 'März');
});

test('if utc is set the date returned from pikaday should be in UTC format', function(assert) {
  var component = this.subject();
  component.set('utc', true);
  var $input = this.render();
  var interactor = openDatepicker($input);

  interactor.selectDate(new Date(2013, 3, 28));

  var date = this.subject().get('value');

  assert.equal(date.getUTCFullYear(), 2013);
  assert.equal(date.getUTCMonth(), 3);
  assert.equal(date.getUTCDate(), 28);
});
<|endoftext|>