<commit_before>
define(
	[
		'jsorrery/NameSpace',
		'jquery',
		'jsorrery/gui/ExportValues',
		'ui',
		'_',
		'vendor/greensock/TweenMax',
		'vendor/greensock/easing/EasePack'
	],
	function(ns, $, ExportValues){
		'use strict';
		var elements = {};

		var BTNS_LABELS = {
			share : '',
			start : ['▶', '‖']
 		};

		var removeElement = function(elId){
			elements[elId] && elements[elId].remove();
		};

		var getContainer = function(id){
			return $('#'+id+'Cont');
		};
		var getLabel = function(id){
			return $('#'+id+'Label');
		};

		var listClicked = function(id, selector, clickedOption, input){
			var val = clickedOption.data('value');
			selector.display.html(clickedOption.html());
			input.val(val).trigger('change');
			ExportValues.setVal(id, val);

		};

		var setupHelp = function(){
			var allHelpContents = $('.helpContent');

			var hideContent = function(content){
				var shown = content.filter('.shown');
				var onDone = $.Deferred();
				if(shown.length>0){
					TweenMax.killTweensOf(shown);
					TweenMax.to(shown, 0.5, {css:{height:1, opacity:0}, onComplete:function(){
							shown.hide();
							shown.removeClass('shown');
							onDone.resolve();
						}
					});
				} else {
					onDone.resolve();
				}
				return onDone.promise();
			};
			var showContent = function(content){
				TweenMax.killTweensOf(content);
				TweenMax.from(content.show().css({height:'auto', opacity:1}), 0.5, {css:{height:1, opacity:0}});
				content.addClass('shown');
			};

			$('.help').on('click.jsorrery', function(e){
				e.preventDefault();
				var _self = $(this);
				var content = _self.data('content');
				if(!content){
					content = allHelpContents.filter('#'+_self.data('for'));
					_self.data('content', content);
					content.find('.close').on('click.jsorrery', function(){
						hideContent(content);
					});
				}

				var onHidden = hideContent(allHelpContents);
				onHidden.then(function(){
					showContent(content)
				});
				return false;
			});
		};

		var dateDisplay;
		var date;

		return {

			PLANET_SCALE_ID : 'planetScale',
			SCENARIO_ID : 'scenario',
			START_ID : 'start',
			SHARE_ID : 'share',
			DATE_ID : 'date',
			LOOKAT_ID : 'lookAt',
			LOOKFROM_ID : 'lookFrom',
			DELTA_T_ID : 'deltaT',

			init : function(universe){
				this.root = $('#gui');
				this.selects = {};

				setupHelp();
			},

			addBtn : function(label, id, callback) {
				removeElement(id);
				label = BTNS_LABELS[id] || label;
				var labelOff;
				var labelOn;
				if(label instanceof Array) {
					labelOff = label[0];
					labelOn = label[1];
				} else {
					labelOff = label;
				}
				var status = false;
				var btn = elements[id] = $('<button id="'+id+'">'+labelOff+'</button>').appendTo(getContainer(id));
				btn.on('click.orrery', function(e){
					e.stopPropagation();
					callback();
					status = !status;
					if(status && labelOn){
						btn.html(labelOn);
					} else {
						btn.html(labelOff);
					}
				});
			},

			addDropdown : function(id, callback){
				removeElement(id);
				var dropdownContainer = getContainer(id).empty().addClass('dropdown');
				var dropdownDisplay = $('
').appendTo(dropdownContainer);
				var selector = this.selects[id] = {
					input : $('<input id="'+id+'_inp">').on('change.orrery', callback),
					display: dropdownDisplay,
					list : $('
').appendTo(dropdownContainer),
					options : {}
				};

				var list = elements[id] = selector.list;
				var input = selector.input;

				this.selects[id].clickHandler = function(e){
					listClicked(id, selector, $(this), input);
				};

				return this.selects[id].input;
			},

			addOption : function(selectName, label, val, isSelected) {
				var sel = this.selects[selectName];
				if(!sel) return;

				var option = sel.options[val] = $('
'+label+'
');
				option.on('click.jsorrery', sel.clickHandler);

				if(sel.list.children().length === 0) {
					sel.input.val(val);
					sel.display.html(label);

					ExportValues.setVal(selectName, val);
				}

				option.appendTo(sel.list);

				var defaultVal = this.defaultSettings && this.defaultSettings[selectName];
				if(isSelected || defaultVal == val) {
					this.pushDefaultsCallbacks(function(){
						listClicked(selectName, sel, option, sel.input)
					});
				}

			},

			toggleOptions : function(selectName, toToggle, isShow){
				var options = this.selects[selectName].options;
				var toggleFcn = isShow ? 'removeClass' : 'addClass';
				var curVal = this.selects[selectName].input.val();
				if(!isShow && toToggle.indexOf(curVal) !== -1) {
					this.selects[selectName].input.val('');
				}
				_.each(toToggle, function(optId){
					options[optId] && options[optId][toggleFcn]('disabled');
					//options[optId] && options[optId].prop('disabled', !isShow);
				});
			},

			addDate : function(onChange){
				if(!dateDisplay) {
					dateDisplay = $('<input>').appendTo(getContainer(this.DATE_ID));
					/*dateDisplay.datepicker({
						dateFormat : $.datepicker.ATOM,
						changeYear : true
					});/**/
				}
				var curDate;
				dateDisplay.off('change').on('change.jsorrery', function(){
					var newDate = new Date(dateDisplay.val());
					if(isNaN(newDate.getTime())){
						newDate = new Date();
					}
					if(curDate != newDate){
						this.setDate(newDate);
						onChange();
					}
					curDate = newDate;
				}.bind(this));

				var defaultDate = this.defaultSettings[this.DATE_ID];
				if(defaultDate){
					defaultDate = new Date(defaultDate);
					this.setDate(defaultDate);
				}

				return dateDisplay;
			},

			setDate : function(d){
				date = d;
				if(d){
					var dStr = d.toISOString();
					ExportValues.setVal(this.DATE_ID, dStr);
					dateDisplay.val(dStr);
					//dateDisplay.val($.datepicker.formatDate( $.datepicker.ATOM, d));
				}
			},

			getDate : function(){
				return date;
			},

			addSlider : function(id, options, onChange) {
				removeElement(id);
				var container = getContainer(id);
				var valDisplay = getLabel(id).find('.valDisplay').text('1');

				var defaultVal = Number(this.defaultSettings[id]);
				var params = {
					slide : function(evt, ui){
						var val = ui.value;
						val = val < 1 ? 1 : val;
						ExportValues.setVal(id, val);
						setSlideValue(val);
					},
					value : defaultVal || (options && options.initial) || 1
				};

				if(options.min) params.min = options.min;
				if(options.max) params.max = options.max;

				var slider = $('
').appendTo(container).slider(params);

				elements[id] = slider;

				var setSlideValue = function(val){
					valDisplay.text(val);
					onChange(val);
				};

				if(defaultVal) {
					this.pushDefaultsCallbacks(function(){
						setSlideValue(defaultVal)
					});
				}

				ExportValues.setVal(id, defaultVal || 1);

				return slider;
			},

			remove : function(id){
				removeElement(id);
			},

			pushDefaultsCallbacks : function(callback){
				this.defaultCallbacks = this.defaultCallbacks || [];
				this.defaultCallbacks.push(callback);
			},

			putDefaults : function(){
				if(!this.defaultCallbacks) return;
				_.each(this.defaultCallbacks, function(callback){
					callback();
				});
				this.defaultCallbacks.length = 0;
			},

			getDefaultCameraPos : function() {

			},

			setDefaults : function(defaultSettings) {
				//console.log(defaultSettings);
				this.defaultSettings = defaultSettings;
			}
		};
	}
);<commit_msg>slider range fix<commit_after>
define(
	[
		'jsorrery/NameSpace',
		'jquery',
		'jsorrery/gui/ExportValues',
		'ui',
		'_',
		'vendor/greensock/TweenMax',
		'vendor/greensock/easing/EasePack'
	],
	function(ns, $, ExportValues){
		'use strict';
		var elements = {};

		var BTNS_LABELS = {
			share : '',
			start : ['▶', '‖']
 		};

		var removeElement = function(elId){
			elements[elId] && elements[elId].remove();
		};

		var getContainer = function(id){
			return $('#'+id+'Cont');
		};
		var getLabel = function(id){
			return $('#'+id+'Label');
		};

		var listClicked = function(id, selector, clickedOption, input){
			var val = clickedOption.data('value');
			selector.display.html(clickedOption.html());
			input.val(val).trigger('change');
			ExportValues.setVal(id, val);

		};

		var setupHelp = function(){
			var allHelpContents = $('.helpContent');

			var hideContent = function(content){
				var shown = content.filter('.shown');
				var onDone = $.Deferred();
				if(shown.length>0){
					TweenMax.killTweensOf(shown);
					TweenMax.to(shown, 0.5, {css:{height:1, opacity:0}, onComplete:function(){
							shown.hide();
							shown.removeClass('shown');
							onDone.resolve();
						}
					});
				} else {
					onDone.resolve();
				}
				return onDone.promise();
			};
			var showContent = function(content){
				TweenMax.killTweensOf(content);
				TweenMax.from(content.show().css({height:'auto', opacity:1}), 0.5, {css:{height:1, opacity:0}});
				content.addClass('shown');
			};

			$('.help').on('click.jsorrery', function(e){
				e.preventDefault();
				var _self = $(this);
				var content = _self.data('content');
				if(!content){
					content = allHelpContents.filter('#'+_self.data('for'));
					_self.data('content', content);
					content.find('.close').on('click.jsorrery', function(){
						hideContent(content);
					});
				}

				var onHidden = hideContent(allHelpContents);
				onHidden.then(function(){
					showContent(content)
				});
				return false;
			});
		};

		var dateDisplay;
		var date;

		return {

			PLANET_SCALE_ID : 'planetScale',
			SCENARIO_ID : 'scenario',
			START_ID : 'start',
			SHARE_ID : 'share',
			DATE_ID : 'date',
			LOOKAT_ID : 'lookAt',
			LOOKFROM_ID : 'lookFrom',
			DELTA_T_ID : 'deltaT',

			init : function(universe){
				this.root = $('#gui');
				this.selects = {};

				setupHelp();
			},

			addBtn : function(label, id, callback) {
				removeElement(id);
				label = BTNS_LABELS[id] || label;
				var labelOff;
				var labelOn;
				if(label instanceof Array) {
					labelOff = label[0];
					labelOn = label[1];
				} else {
					labelOff = label;
				}
				var status = false;
				var btn = elements[id] = $('<button id="'+id+'">'+labelOff+'</button>').appendTo(getContainer(id));
				btn.on('click.orrery', function(e){
					e.stopPropagation();
					callback();
					status = !status;
					if(status && labelOn){
						btn.html(labelOn);
					} else {
						btn.html(labelOff);
					}
				});
			},

			addDropdown : function(id, callback){
				removeElement(id);
				var dropdownContainer = getContainer(id).empty().addClass('dropdown');
				var dropdownDisplay = $('
').appendTo(dropdownContainer);
				var selector = this.selects[id] = {
					input : $('<input id="'+id+'_inp">').on('change.orrery', callback),
					display: dropdownDisplay,
					list : $('
').appendTo(dropdownContainer),
					options : {}
				};

				var list = elements[id] = selector.list;
				var input = selector.input;

				this.selects[id].clickHandler = function(e){
					listClicked(id, selector, $(this), input);
				};

				return this.selects[id].input;
			},

			addOption : function(selectName, label, val, isSelected) {
				var sel = this.selects[selectName];
				if(!sel) return;

				var option = sel.options[val] = $('
'+label+'
');
				option.on('click.jsorrery', sel.clickHandler);

				if(sel.list.children().length === 0) {
					sel.input.val(val);
					sel.display.html(label);

					ExportValues.setVal(selectName, val);
				}

				option.appendTo(sel.list);

				var defaultVal = this.defaultSettings && this.defaultSettings[selectName];
				if(isSelected || defaultVal == val) {
					this.pushDefaultsCallbacks(function(){
						listClicked(selectName, sel, option, sel.input)
					});
				}

			},

			toggleOptions : function(selectName, toToggle, isShow){
				var options = this.selects[selectName].options;
				var toggleFcn = isShow ? 'removeClass' : 'addClass';
				var curVal = this.selects[selectName].input.val();
				if(!isShow && toToggle.indexOf(curVal) !== -1) {
					this.selects[selectName].input.val('');
				}
				_.each(toToggle, function(optId){
					options[optId] && options[optId][toggleFcn]('disabled');
					//options[optId] && options[optId].prop('disabled', !isShow);
				});
			},

			addDate : function(onChange){
				if(!dateDisplay) {
					dateDisplay = $('<input>').appendTo(getContainer(this.DATE_ID));
					/*dateDisplay.datepicker({
						dateFormat : $.datepicker.ATOM,
						changeYear : true
					});/**/
				}
				var curDate;
				dateDisplay.off('change').on('change.jsorrery', function(){
					var newDate = new Date(dateDisplay.val());
					if(isNaN(newDate.getTime())){
						newDate = new Date();
					}
					if(curDate != newDate){
						this.setDate(newDate);
						onChange();
					}
					curDate = newDate;
				}.bind(this));

				var defaultDate = this.defaultSettings[this.DATE_ID];
				if(defaultDate){
					defaultDate = new Date(defaultDate);
					this.setDate(defaultDate);
				}

				return dateDisplay;
			},

			setDate : function(d){
				date = d;
				if(d){
					var dStr = d.toISOString();
					ExportValues.setVal(this.DATE_ID, dStr);
					dateDisplay.val(dStr);
					//dateDisplay.val($.datepicker.formatDate( $.datepicker.ATOM, d));
				}
			},

			getDate : function(){
				return date;
			},

			addSlider : function(id, options, onChange) {
				removeElement(id);
				var container = getContainer(id);
				var valDisplay = getLabel(id).find('.valDisplay').text('1');

				var defaultVal = Number(this.defaultSettings[id]);
				var params = {
					slide : function(evt, ui){
						var val = ui.value;
						val = val < 1 ? 1 : val;
						ExportValues.setVal(id, val);
						setSlideValue(val);
					},
					value : defaultVal || (options && options.initial) || 1
				};

				if(options && options.min) params.min = options.min;
				if(options && options.max) params.max = options.max;

				var slider = $('
').appendTo(container).slider(params);

				elements[id] = slider;

				var setSlideValue = function(val){
					valDisplay.text(val);
					onChange(val);
				};

				if(defaultVal) {
					this.pushDefaultsCallbacks(function(){
						setSlideValue(defaultVal)
					});
				}

				ExportValues.setVal(id, defaultVal || 1);

				return slider;
			},

			remove : function(id){
				removeElement(id);
			},

			pushDefaultsCallbacks : function(callback){
				this.defaultCallbacks = this.defaultCallbacks || [];
				this.defaultCallbacks.push(callback);
			},

			putDefaults : function(){
				if(!this.defaultCallbacks) return;
				_.each(this.defaultCallbacks, function(callback){
					callback();
				});
				this.defaultCallbacks.length = 0;
			},

			getDefaultCameraPos : function() {

			},

			setDefaults : function(defaultSettings) {
				//console.log(defaultSettings);
				this.defaultSettings = defaultSettings;
			}
		};
	}
);<|endoftext|>


<commit_before>/* jshint esversion:6, node: true */

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();

app.set('port', (process.env.PORT || 5000));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}));

// parse application/json
app.use(bodyParser.json());

// index
app.get('/', function (req, res) {
	res.send('hello world i am a secret bot');
});

// for facebook verification
app.get('/webhook/', function (req, res) {
	if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
		res.send(req.query['hub.challenge']);
	} else {
		res.send('Error, wrong token');
	}
});

// to post data
app.post('/webhook/', function (req, res) {
	var results;

	let messaging_events = req.body.entry[0].messaging;
	for (let i = 0; i < messaging_events.length; i++) {
		let event = req.body.entry[0].messaging[i];
		let sender = event.sender.id;

		if (event.message && event.message.text) {
			let text = event.message.text;
			if (text === 'Generic') {
				sendGenericMessage(sender);
				continue;
			}

			else if (text == 'cookies'){
				var headers = {
				    'Authorization': 'bearer fd887ce5-7b15-4c1e-93a0-dc91ce883ec6'
				};

				var options = {
				    url: 'https://www.loblaws.ca/ecommerce/v2/loblaw/products/search?q=apple&page=0&pageSize=10&sort=recommended&filters=category:LSL001006000000',
				    headers: headers
				};
				function callback(error, response, body) {
				    if (!error && response.statusCode == 200) {
				        //console.log(body);
				        var resp = JSON.parse(body);
				        results = resp["searchResults"];
				        console.log(results[0]);
				        console.log(results.products[0].productName);

				        sendProductMessage(sender, results);
				    }
				}

				request(options, callback);

			}
			sendTextMessage(sender, "echo: " + text.substring(0, 200));
		}
		if (event.postback) {
			let text = JSON.stringify(event.postback);
			sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token);
			continue;
		}
	}
	res.sendStatus(200);
});

// recommended to inject access tokens as environmental variables, e.g.
const token = process.env.PAGE_ACCESS_TOKEN;
//const token = "<PAGE_ACCESS_TOKEN>"

function sendTextMessage(sender, text) {
	let messageData = { text:text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendGenericMessage(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": "First card",
					"subtitle": "Element #1 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendProductMessage(sender, results) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": results.products[0].productName,
					"subtitle": results.products[0].description,
					"image_url": results.products[0].primaryIm,
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

// spin spin sugar
app.listen(app.get('port'), function() {
	console.log('running on port', app.get('port'));
});
<commit_msg>heroku<commit_after>/* jshint esversion:6, node: true */

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const request = require('request');
const app = express();

app.set('port', (process.env.PORT || 5000));

// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({extended: false}));

// parse application/json
app.use(bodyParser.json());

// index
app.get('/', function (req, res) {
	res.send('hello world i am a secret bot');
});

// for facebook verification
app.get('/webhook/', function (req, res) {
	if (req.query['hub.verify_token'] === 'my_voice_is_my_password_verify_me') {
		res.send(req.query['hub.challenge']);
	} else {
		res.send('Error, wrong token');
	}
});

// to post data
app.post('/webhook/', function (req, res) {
	var results;

	let messaging_events = req.body.entry[0].messaging;
	for (let i = 0; i < messaging_events.length; i++) {
		let event = req.body.entry[0].messaging[i];
		let sender = event.sender.id;

		if (event.message && event.message.text) {
			let text = event.message.text;
			if (text === 'Generic') {
				sendGenericMessage(sender);
				continue;
			}

			else if (text == 'cookies'){
				var headers = {
				    'Authorization': 'bearer fd887ce5-7b15-4c1e-93a0-dc91ce883ec6'
				};

				var options = {
				    url: 'https://www.loblaws.ca/ecommerce/v2/loblaw/products/search?q=apple&page=0&pageSize=10&sort=recommended&filters=category:LSL001006000000',
				    headers: headers
				};
				function callback(error, response, body) {
				    if (!error && response.statusCode == 200) {
				        //console.log(body);
				        var resp = JSON.parse(body);
				        results = resp["searchResults"];
				        console.log(results[0]);
				        console.log(results.products[0].productName);

				        sendProductMessage(sender, results);
				    }
				}

				request(options, callback);

			}
			sendTextMessage(sender, "echo: " + text.substring(0, 200));
		}
		if (event.postback) {
			let text = JSON.stringify(event.postback);
			sendTextMessage(sender, "Postback received: "+text.substring(0, 200), token);
			continue;
		}
	}
	res.sendStatus(200);
});

// recommended to inject access tokens as environmental variables, e.g.
const token = process.env.PAGE_ACCESS_TOKEN;
//const token = "<PAGE_ACCESS_TOKEN>"

function sendTextMessage(sender, text) {
	let messageData = { text:text };

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendGenericMessage(sender) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": "First card",
					"subtitle": "Element #1 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/rift.png",
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

function sendProductMessage(sender, results) {
	let messageData = {
		"attachment": {
			"type": "template",
			"payload": {
				"template_type": "generic",
				"elements": [{
					"title": results.products[0].productName,
					"subtitle": results.products[0].description,
					"image_url": results.products[0].primaryImage,
					"buttons": [{
						"type": "web_url",
						"url": "https://www.messenger.com",
						"title": "web url"
					}, {
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for first element in a generic bubble",
					}],
				}, {
					"title": "Second card",
					"subtitle": "Element #2 of an hscroll",
					"image_url": "http://messengerdemo.parseapp.com/img/gearvr.png",
					"buttons": [{
						"type": "postback",
						"title": "Postback",
						"payload": "Payload for second element in a generic bubble",
					}],
				}]
			}
		}
	};

	request({
		url: 'https://graph.facebook.com/v2.6/me/messages',
		qs: {access_token:token},
		method: 'POST',
		json: {
			recipient: {id:sender},
			message: messageData,
		}
	}, function(error, response, body) {
		if (error) {
			console.log('Error sending messages: ', error);
		} else if (response.body.error) {
			console.log('Error: ', response.body.error);
		}
	});
}

// spin spin sugar
app.listen(app.get('port'), function() {
	console.log('running on port', app.get('port'));
});
<|endoftext|>


<commit_before><commit_msg>feat: add `req.json`<commit_after><|endoftext|>


<commit_before>var Util, DOM, CloudFunc;

(function(scope, Util, DOM, CloudFunc) {
    'use strict';

    scope.CloudCmd = new CloudCmdProto(Util, DOM, CloudFunc);

    function CloudCmdProto(Util, DOM, CloudFunc) {
        var Key, Config, Modules, Extensions,
            FileTemplate, PathTemplate, Listeners,
            DIR_HTML                = '/html/',
            DIR_HTML_FS             = DIR_HTML + 'fs/',
            DIR_JSON                = '/json/',

            Images                  = DOM.Images,
            Info                    = DOM.CurrentInfo,
            CloudCmd                = this,
            Storage                 = DOM.Storage;

        this.MousePosition          = {};
        this.LIBDIR                 = '/lib/';
        this.LIBDIRCLIENT           = '/lib/client/';
        this.MIN_ONE_PANEL_WIDTH    = 1155;
        this.OLD_BROWSER            = false;
        this.HOST                   = location.origin ||
                                      location.protocol + '//' + location.host;
        /**
         * Функция привязываеться ко всем ссылкам и
         *  загружает содержимое каталогов
         *
         * @param params - {
         *          paramLink - ссылка
         *          needRefresh - необходимость обязательной загрузки данных с сервера
         *          panel
         *      }
         * @param event
         */
        this.loadDir                = function(params) {
            var link, imgPosition, panelChanged, pathParams,
                isRefresh, panel, nohistory,
                p               = params,
                currentLink     = DOM.getCurrentLink(),
                href            = currentLink.href;

            if (params) {
                pathParams      = p.path;
                isRefresh       = p.isRefresh;
                panel           = p.panel;
                nohistory       = p.nohistory;
            }

            if (pathParams)
                link = pathParams;
            else
                link = Util.rmStr(href, CloudCmd.HOST);

            if (link || currentLink.target !== '_blank') {
                if (panel && panel !== Info.panel) {
                    DOM.changePanel();
                    panelChanged = true;
                }

                if (panelChanged || isRefresh)
                    imgPosition = {
                        top: true
                    };

                Images.showLoad(imgPosition);

                /* загружаем содержимое каталога */
                ajaxLoad(link, {
                    refresh     : isRefresh,
                    nohistory   : nohistory
                }, panel);
            }
        };

        /**
         * функция устанавливает курсор на каталог
         * с которого мы пришли, если мы поднялись
         * в верх по файловой структуре
         * @param pDirName - имя каталога с которого мы пришли
         */
        function currentToParent(dirName) {
            var rootDir;
            /* убираем слэш с имени каталога */
            dirName     = Util.rmStr(dirName, '/');
            rootDir     = DOM.getCurrentFileByName(dirName);

            if (rootDir)
                DOM.setCurrentFile(rootDir);
        }

        /**
         * function load modules
         * @pParams = {name, path, func, dobefore, arg}
         */
        function loadModule(params) {
            var name, path, func, doBefore, slash, afterSlash,
                isContain;

            if (params) {
                name        = params.name,
                path        = params.path,
                func        = params.func,
                doBefore    = params.dobefore;

                if (path && !name) {
                    name = Util.getStrBigFirst(path);
                    name = Util.rmStr(name, '.js');

                    slash = name.indexOf('/');
                    if (slash > 0) {
                        afterSlash = name.substr(slash);
                        name = Util.rmStr(name, afterSlash);
                    }
                }

                isContain = Util.isContainStr(path, '.js');

                if (!isContain)
                    path += '.js';

                if (!CloudCmd[name]) {
                    CloudCmd[name] = function() {
                        var pathFull    = CloudCmd.LIBDIRCLIENT + path,
                            args        = arguments;

                        Util.exec(doBefore);

                        return DOM.jsload(pathFull, func ||
                            function() {
                                var Proto = CloudCmd[name];

                                if (Util.isFunction(Proto))
                                    CloudCmd[name] = Util.applyConstructor(Proto, args);
                            });
                    };

                    CloudCmd[name].show = CloudCmd[name];
                }
            }
        }

        /** Конструктор CloudClient, который
         * выполняет весь функционал по
         * инициализации
         */
        this.init                    = function() {
            var callback = function() {
                    Util.loadOnLoad([
                        initModules,
                        baseInit,
                        Util.bind(CloudCmd.route, location.hash)
                    ]);
                },

                func = function(callback) {
                    var src = CloudCmd.LIBDIRCLIENT + 'polyfill.js';

                    CloudCmd.OLD_BROWSER = true;

                    DOM.jqueryLoad(function() {
                        DOM.jsload(src, callback);
                    });
                };

            Util.ifExec(document.body.scrollIntoViewIfNeeded, callback, func);
        };

        this.route                   = function(path) {
            var module, file, current, msg,
                query   = path.split('/');

            if (path) {
                module      = query[0];
                module      = Util.slice(module, 1).join('');
                module      = Util.getStrBigFirst(module);

                file        = query[1];
                current     = DOM.getCurrentFileByName(file);

                if (file && !current) {
                    msg = CloudFunc.formatMsg('set current file', file, 'error');
                    Util.log(msg);
                } else {
                    DOM.setCurrentFile(current);
                    CloudCmd.execFromModule(module, 'show');
                }
            }
        };

        function initModules(callback) {
            Util.ifExec(CloudCmd.Key, function() {
                Key          = new CloudCmd.Key();
                CloudCmd.Key = Key;
                Key.bind();
            }, function(callback) {
                loadModule({
                    /* привязываем клавиши к функциям */
                    path  : 'key.js',
                    func : callback
                 });
             });

            CloudCmd.getModules(function(modules) {
                var storageObj, mod, path,
                    STORAGE     = 'storage',
                    showLoad    = Images.showLoad.bind(Images),

                    doBefore    = {
                        'edit'                  : showLoad,
                        'menu'                  : showLoad,
                        'storage/_filepicker'   : showLoad
                    },

                    load = function(name, path, func) {
                        loadModule({
                            name        : name,
                            path        : path,
                            dobefore    : func
                        });
                    };

                if (!modules)
                    modules = [];

                modules.forEach(function(module) {
                    if (Util.isString(module))
                        load(null, module, doBefore[module]);
                });

                storageObj = Util.findObjByNameInArr(modules, STORAGE),
                mod        = Util.getNamesFromObjArray(storageObj);

                mod.forEach(function(name) {
                    path = STORAGE + '/_' + name.toLowerCase();

                    load(name, path, doBefore[path]);
                });

                Util.exec(callback);
            });
        }

        function baseInit(pCallBack) {
            var files       = DOM.getFiles(),
                LEFT        = CloudFunc.PANEL_LEFT,
                RIGHT       = CloudFunc.PANEL_RIGHT;

            /* выделяем строку с первым файлом                                  */
            if (files)
                DOM.setCurrentFile(files[0]);

            Listeners = CloudCmd.Listeners;
            Listeners.init();
            /* загружаем Google Analytics */
            Listeners.analytics();
            Listeners.changeLinks(LEFT);
            Listeners.changeLinks(RIGHT);

            Listeners.setOnPanel(LEFT);
            Listeners.setOnPanel(RIGHT);

            Listeners.initKeysPanel();

            CloudCmd.getConfig(function(config) {
                var localStorage    = config.localStorage,
                    dirPath         = DOM.getCurrentDirPath();

                /* устанавливаем переменную доступности кэша                    */
                Storage.setAllowed(localStorage);
                /* Устанавливаем кэш корневого каталога                         */

                dirPath     = CloudFunc.rmLastSlash(dirPath) || '/';

                Storage.get(dirPath, function(data) {
                    if (!data) {
                        data    = getJSONfromFileTable();
                        Storage.set(dirPath, data);
                    }
                });
            });

            Util.exec(CloudCmd.Key);
            Util.exec(pCallBack);
        }

        this.getTemplate = function(data, name, callback) {
            var path    = DIR_HTML + name +'.html',
                func    = getSystemFile(data, path);

            func(callback);
        };

        function getSystemFile(pGlobal, pURL) {

            function lGetSysFile(callback) {
                Util.ifExec(pGlobal, callback, function() {
                    DOM.ajax({
                        url     : pURL,
                        success : function(pLocal) {
                            pGlobal = pLocal;
                            Util.exec(callback, pLocal);
                        }
                    });
                });
            }

            return lGetSysFile;
        }

        this.setConfig              = function(config) { Config = config; };
        this.getConfig              = function(callback) {
            Util.ifExec(Config, callback, function() {
                var RESTful = DOM.RESTful;

                RESTful.Config.read(function(config) {
                    Config = config;
                    callback(config);
                });
            });
        };

        this.getModules             = getSystemFile(Modules,        DIR_JSON    + 'modules.json');
        this.getExt                 = getSystemFile(Extensions,     DIR_JSON    + 'ext.json');
        this.getFileTemplate        = getSystemFile(FileTemplate,   DIR_HTML_FS + 'file.html');
        this.getPathTemplate        = getSystemFile(PathTemplate,   DIR_HTML_FS + 'path.html');
        this.getLinkTemplate        = getSystemFile(PathTemplate,   DIR_HTML_FS + 'link.html');

        this.execFromModule         = function(moduleName, funcName, params) {
            var obj     = CloudCmd[moduleName],
                isObj   = Util.isObject(obj);

            Util.ifExec(isObj,
                function() {
                    var obj     = CloudCmd[moduleName],
                        func    = obj[funcName];

                    Util.exec(func, params);
                },

                function(callback) {
                    Util.exec(obj, callback);
                });
        };

        this.refresh                =  function(current, panelParam) {
            var NEEDREFRESH     = true,
                panel           = panelParam || current && current.parentElement,
                path            = DOM.getCurrentDirPath(panel),
                link            = CloudFunc.FS + path,
                notSlashlLink   = CloudFunc.rmLastSlash(link);

            CloudCmd.loadDir({
                path        : notSlashlLink,
                isRefresh   : NEEDREFRESH,
                panel: panel
            });
        };

        /**
         * Функция загружает json-данные о Файловой Системе
         * через ajax-запрос.
         * @param path - каталог для чтения
         * @param pOptions
         * { refresh, nohistory } - необходимость обновить данные о каталоге
         */
        function ajaxLoad(path, options, panel) {
            var SLASH       = '/',
                fsPath      = decodeURI(path),
                cleanPath   = Util.rmStrOnce(fsPath, CloudFunc.FS) || SLASH;

            if (!options)
                options    = {};

            Util.log ('reading dir: "' + cleanPath + '";');

            Storage.get(cleanPath, function(json) {
                var RESTful     = DOM.RESTful,
                    obj         = Util.parseJSON(json),
                    isRefresh   = options.refresh,
                    nohistory   = options.nohistory;

                if (!isRefresh && json)
                    createFileTable(obj, panel, nohistory);
                else
                    RESTful.read(cleanPath, 'json', function(obj) {
                        createFileTable(obj, panel, nohistory);
                        Storage.set(cleanPath, obj);
                    });
            });
        }

        /**
         * Функция строит файловую таблицу
         * @param json  - данные о файлах
         * @param panelParam
         * @param nohistory
         */
        function createFileTable(json, panelParam, nohistory) {
            var files,
                panel           = panelParam || DOM.getPanel(),
                /* getting current element if was refresh */
                path            = DOM.getCurrentDirPath(panel),
                wasRefresh      = path === json.path,
                funcs           = [
                    CloudCmd.getFileTemplate,
                    CloudCmd.getPathTemplate,
                    CloudCmd.getLinkTemplate
                ];

            Util.asyncCall(funcs, function(templFile, templPath, templLink) {
                var n, found, varCurrent, varName, current,
                    dir     = DOM.getCurrentDirName(),
                    name    = DOM.getCurrentName(),
                    i       = panel.childNodes.length;

                Listeners.unSetOnPanel(panel.id);

                while(i--)
                    panel.removeChild(panel.lastChild);

                panel.innerHTML = CloudFunc.buildFromJSON(json, templFile, templPath, templLink);
                files           = DOM.getFiles(panel);

                /* searching current file */
                if (wasRefresh) {
                    n = files.length;

                    for (i = 0; i < n ; i++) {
                        varCurrent  = files[i],
                        varName     = DOM.getCurrentName(varCurrent);
                        found       = varName === name;

                        if (found) {
                            current    = files[i];
                            break;
                        }
                    }
                }
                if (!found) /* .. */
                    current = files[0];

                DOM.setCurrentFile(current, {
                    nohistory: nohistory
                });

                Listeners.changeLinks(panel.id);
                Listeners.setOnPanel(panel.id);

                if (name === '..' && dir !== '/')
                    currentToParent(dir);
            });
        };

        /**
         * Функция генерирует JSON из html-таблицы файлов и
         * используеться при первом заходе в корень
         */
        function getJSONfromFileTable() {
            var current, name, size, owner, mode, ret,
                path        = DOM.getCurrentDirPath(),
                infoFiles   = Info.files,

                fileTable   = {
                    path    : path,
                    files   : []
                },

                files       = fileTable.files,

                i, n        = infoFiles.length;

            for (i = 0; i < n; i++) {
                current     = infoFiles[i];
                name        = DOM.getCurrentName(current);
                size        = DOM.getCurrentSize(current);
                owner       = DOM.getCurrentOwner(current);
                mode        = DOM.getCurrentMode(current);

                mode        = CloudFunc.getNumericPermissions(mode);

                if (name !== '..')
                    files.push({
                        name    : name,
                        size    : size,
                        mode    : mode,
                        owner   : owner
                    });
            }

            ret = Util.stringifyJSON(fileTable);

            return ret;
        }

        this.goToParentDir          = function() {
            var path        = Info.dirPath,
                parentPath  = Info.parentDirPath;

            if (path !== parentPath) {
                path    = parentPath;
                path    = CloudFunc.FS + CloudFunc.rmLastSlash(path);

                CloudCmd.loadDir({
                    path: path
                });
            }
        };

    }
})(this, Util, DOM, CloudFunc);
<commit_msg>chore(client) rm ";"<commit_after>var Util, DOM, CloudFunc;

(function(scope, Util, DOM, CloudFunc) {
    'use strict';

    scope.CloudCmd = new CloudCmdProto(Util, DOM, CloudFunc);

    function CloudCmdProto(Util, DOM, CloudFunc) {
        var Key, Config, Modules, Extensions,
            FileTemplate, PathTemplate, Listeners,
            DIR_HTML                = '/html/',
            DIR_HTML_FS             = DIR_HTML + 'fs/',
            DIR_JSON                = '/json/',

            Images                  = DOM.Images,
            Info                    = DOM.CurrentInfo,
            CloudCmd                = this,
            Storage                 = DOM.Storage;

        this.MousePosition          = {};
        this.LIBDIR                 = '/lib/';
        this.LIBDIRCLIENT           = '/lib/client/';
        this.MIN_ONE_PANEL_WIDTH    = 1155;
        this.OLD_BROWSER            = false;
        this.HOST                   = location.origin ||
                                      location.protocol + '//' + location.host;
        /**
         * Функция привязываеться ко всем ссылкам и
         *  загружает содержимое каталогов
         *
         * @param params - {
         *          paramLink - ссылка
         *          needRefresh - необходимость обязательной загрузки данных с сервера
         *          panel
         *      }
         * @param event
         */
        this.loadDir                = function(params) {
            var link, imgPosition, panelChanged, pathParams,
                isRefresh, panel, nohistory,
                p               = params,
                currentLink     = DOM.getCurrentLink(),
                href            = currentLink.href;

            if (params) {
                pathParams      = p.path;
                isRefresh       = p.isRefresh;
                panel           = p.panel;
                nohistory       = p.nohistory;
            }

            if (pathParams)
                link = pathParams;
            else
                link = Util.rmStr(href, CloudCmd.HOST);

            if (link || currentLink.target !== '_blank') {
                if (panel && panel !== Info.panel) {
                    DOM.changePanel();
                    panelChanged = true;
                }

                if (panelChanged || isRefresh)
                    imgPosition = {
                        top: true
                    };

                Images.showLoad(imgPosition);

                /* загружаем содержимое каталога */
                ajaxLoad(link, {
                    refresh     : isRefresh,
                    nohistory   : nohistory
                }, panel);
            }
        };

        /**
         * функция устанавливает курсор на каталог
         * с которого мы пришли, если мы поднялись
         * в верх по файловой структуре
         * @param pDirName - имя каталога с которого мы пришли
         */
        function currentToParent(dirName) {
            var rootDir;
            /* убираем слэш с имени каталога */
            dirName     = Util.rmStr(dirName, '/');
            rootDir     = DOM.getCurrentFileByName(dirName);

            if (rootDir)
                DOM.setCurrentFile(rootDir);
        }

        /**
         * function load modules
         * @pParams = {name, path, func, dobefore, arg}
         */
        function loadModule(params) {
            var name, path, func, doBefore, slash, afterSlash,
                isContain;

            if (params) {
                name        = params.name,
                path        = params.path,
                func        = params.func,
                doBefore    = params.dobefore;

                if (path && !name) {
                    name = Util.getStrBigFirst(path);
                    name = Util.rmStr(name, '.js');

                    slash = name.indexOf('/');
                    if (slash > 0) {
                        afterSlash = name.substr(slash);
                        name = Util.rmStr(name, afterSlash);
                    }
                }

                isContain = Util.isContainStr(path, '.js');

                if (!isContain)
                    path += '.js';

                if (!CloudCmd[name]) {
                    CloudCmd[name] = function() {
                        var pathFull    = CloudCmd.LIBDIRCLIENT + path,
                            args        = arguments;

                        Util.exec(doBefore);

                        return DOM.jsload(pathFull, func ||
                            function() {
                                var Proto = CloudCmd[name];

                                if (Util.isFunction(Proto))
                                    CloudCmd[name] = Util.applyConstructor(Proto, args);
                            });
                    };

                    CloudCmd[name].show = CloudCmd[name];
                }
            }
        }

        /** Конструктор CloudClient, который
         * выполняет весь функционал по
         * инициализации
         */
        this.init                    = function() {
            var callback = function() {
                    Util.loadOnLoad([
                        initModules,
                        baseInit,
                        Util.bind(CloudCmd.route, location.hash)
                    ]);
                },

                func = function(callback) {
                    var src = CloudCmd.LIBDIRCLIENT + 'polyfill.js';

                    CloudCmd.OLD_BROWSER = true;

                    DOM.jqueryLoad(function() {
                        DOM.jsload(src, callback);
                    });
                };

            Util.ifExec(document.body.scrollIntoViewIfNeeded, callback, func);
        };

        this.route                   = function(path) {
            var module, file, current, msg,
                query   = path.split('/');

            if (path) {
                module      = query[0];
                module      = Util.slice(module, 1).join('');
                module      = Util.getStrBigFirst(module);

                file        = query[1];
                current     = DOM.getCurrentFileByName(file);

                if (file && !current) {
                    msg = CloudFunc.formatMsg('set current file', file, 'error');
                    Util.log(msg);
                } else {
                    DOM.setCurrentFile(current);
                    CloudCmd.execFromModule(module, 'show');
                }
            }
        };

        function initModules(callback) {
            Util.ifExec(CloudCmd.Key, function() {
                Key          = new CloudCmd.Key();
                CloudCmd.Key = Key;
                Key.bind();
            }, function(callback) {
                loadModule({
                    /* привязываем клавиши к функциям */
                    path  : 'key.js',
                    func : callback
                 });
             });

            CloudCmd.getModules(function(modules) {
                var storageObj, mod, path,
                    STORAGE     = 'storage',
                    showLoad    = Images.showLoad.bind(Images),

                    doBefore    = {
                        'edit'                  : showLoad,
                        'menu'                  : showLoad,
                        'storage/_filepicker'   : showLoad
                    },

                    load = function(name, path, func) {
                        loadModule({
                            name        : name,
                            path        : path,
                            dobefore    : func
                        });
                    };

                if (!modules)
                    modules = [];

                modules.forEach(function(module) {
                    if (Util.isString(module))
                        load(null, module, doBefore[module]);
                });

                storageObj = Util.findObjByNameInArr(modules, STORAGE),
                mod        = Util.getNamesFromObjArray(storageObj);

                mod.forEach(function(name) {
                    path = STORAGE + '/_' + name.toLowerCase();

                    load(name, path, doBefore[path]);
                });

                Util.exec(callback);
            });
        }

        function baseInit(pCallBack) {
            var files       = DOM.getFiles(),
                LEFT        = CloudFunc.PANEL_LEFT,
                RIGHT       = CloudFunc.PANEL_RIGHT;

            /* выделяем строку с первым файлом                                  */
            if (files)
                DOM.setCurrentFile(files[0]);

            Listeners = CloudCmd.Listeners;
            Listeners.init();
            /* загружаем Google Analytics */
            Listeners.analytics();
            Listeners.changeLinks(LEFT);
            Listeners.changeLinks(RIGHT);

            Listeners.setOnPanel(LEFT);
            Listeners.setOnPanel(RIGHT);

            Listeners.initKeysPanel();

            CloudCmd.getConfig(function(config) {
                var localStorage    = config.localStorage,
                    dirPath         = DOM.getCurrentDirPath();

                /* устанавливаем переменную доступности кэша                    */
                Storage.setAllowed(localStorage);
                /* Устанавливаем кэш корневого каталога                         */

                dirPath     = CloudFunc.rmLastSlash(dirPath) || '/';

                Storage.get(dirPath, function(data) {
                    if (!data) {
                        data    = getJSONfromFileTable();
                        Storage.set(dirPath, data);
                    }
                });
            });

            Util.exec(CloudCmd.Key);
            Util.exec(pCallBack);
        }

        this.getTemplate = function(data, name, callback) {
            var path    = DIR_HTML + name +'.html',
                func    = getSystemFile(data, path);

            func(callback);
        };

        function getSystemFile(pGlobal, pURL) {

            function lGetSysFile(callback) {
                Util.ifExec(pGlobal, callback, function() {
                    DOM.ajax({
                        url     : pURL,
                        success : function(pLocal) {
                            pGlobal = pLocal;
                            Util.exec(callback, pLocal);
                        }
                    });
                });
            }

            return lGetSysFile;
        }

        this.setConfig              = function(config) { Config = config; };
        this.getConfig              = function(callback) {
            Util.ifExec(Config, callback, function() {
                var RESTful = DOM.RESTful;

                RESTful.Config.read(function(config) {
                    Config = config;
                    callback(config);
                });
            });
        };

        this.getModules             = getSystemFile(Modules,        DIR_JSON    + 'modules.json');
        this.getExt                 = getSystemFile(Extensions,     DIR_JSON    + 'ext.json');
        this.getFileTemplate        = getSystemFile(FileTemplate,   DIR_HTML_FS + 'file.html');
        this.getPathTemplate        = getSystemFile(PathTemplate,   DIR_HTML_FS + 'path.html');
        this.getLinkTemplate        = getSystemFile(PathTemplate,   DIR_HTML_FS + 'link.html');

        this.execFromModule         = function(moduleName, funcName, params) {
            var obj     = CloudCmd[moduleName],
                isObj   = Util.isObject(obj);

            Util.ifExec(isObj,
                function() {
                    var obj     = CloudCmd[moduleName],
                        func    = obj[funcName];

                    Util.exec(func, params);
                },

                function(callback) {
                    Util.exec(obj, callback);
                });
        };

        this.refresh                =  function(current, panelParam) {
            var NEEDREFRESH     = true,
                panel           = panelParam || current && current.parentElement,
                path            = DOM.getCurrentDirPath(panel),
                link            = CloudFunc.FS + path,
                notSlashlLink   = CloudFunc.rmLastSlash(link);

            CloudCmd.loadDir({
                path        : notSlashlLink,
                isRefresh   : NEEDREFRESH,
                panel: panel
            });
        };

        /**
         * Функция загружает json-данные о Файловой Системе
         * через ajax-запрос.
         * @param path - каталог для чтения
         * @param pOptions
         * { refresh, nohistory } - необходимость обновить данные о каталоге
         */
        function ajaxLoad(path, options, panel) {
            var SLASH       = '/',
                fsPath      = decodeURI(path),
                cleanPath   = Util.rmStrOnce(fsPath, CloudFunc.FS) || SLASH;

            if (!options)
                options    = {};

            Util.log ('reading dir: "' + cleanPath + '";');

            Storage.get(cleanPath, function(json) {
                var RESTful     = DOM.RESTful,
                    obj         = Util.parseJSON(json),
                    isRefresh   = options.refresh,
                    nohistory   = options.nohistory;

                if (!isRefresh && json)
                    createFileTable(obj, panel, nohistory);
                else
                    RESTful.read(cleanPath, 'json', function(obj) {
                        createFileTable(obj, panel, nohistory);
                        Storage.set(cleanPath, obj);
                    });
            });
        }

        /**
         * Функция строит файловую таблицу
         * @param json  - данные о файлах
         * @param panelParam
         * @param nohistory
         */
        function createFileTable(json, panelParam, nohistory) {
            var files,
                panel           = panelParam || DOM.getPanel(),
                /* getting current element if was refresh */
                path            = DOM.getCurrentDirPath(panel),
                wasRefresh      = path === json.path,
                funcs           = [
                    CloudCmd.getFileTemplate,
                    CloudCmd.getPathTemplate,
                    CloudCmd.getLinkTemplate
                ];

            Util.asyncCall(funcs, function(templFile, templPath, templLink) {
                var n, found, varCurrent, varName, current,
                    dir     = DOM.getCurrentDirName(),
                    name    = DOM.getCurrentName(),
                    i       = panel.childNodes.length;

                Listeners.unSetOnPanel(panel.id);

                while(i--)
                    panel.removeChild(panel.lastChild);

                panel.innerHTML = CloudFunc.buildFromJSON(json, templFile, templPath, templLink);
                files           = DOM.getFiles(panel);

                /* searching current file */
                if (wasRefresh) {
                    n = files.length;

                    for (i = 0; i < n ; i++) {
                        varCurrent  = files[i],
                        varName     = DOM.getCurrentName(varCurrent);
                        found       = varName === name;

                        if (found) {
                            current    = files[i];
                            break;
                        }
                    }
                }
                if (!found) /* .. */
                    current = files[0];

                DOM.setCurrentFile(current, {
                    nohistory: nohistory
                });

                Listeners.changeLinks(panel.id);
                Listeners.setOnPanel(panel.id);

                if (name === '..' && dir !== '/')
                    currentToParent(dir);
            });
        }

        /**
         * Функция генерирует JSON из html-таблицы файлов и
         * используеться при первом заходе в корень
         */
        function getJSONfromFileTable() {
            var current, name, size, owner, mode, ret,
                path        = DOM.getCurrentDirPath(),
                infoFiles   = Info.files,

                fileTable   = {
                    path    : path,
                    files   : []
                },

                files       = fileTable.files,

                i, n        = infoFiles.length;

            for (i = 0; i < n; i++) {
                current     = infoFiles[i];
                name        = DOM.getCurrentName(current);
                size        = DOM.getCurrentSize(current);
                owner       = DOM.getCurrentOwner(current);
                mode        = DOM.getCurrentMode(current);

                mode        = CloudFunc.getNumericPermissions(mode);

                if (name !== '..')
                    files.push({
                        name    : name,
                        size    : size,
                        mode    : mode,
                        owner   : owner
                    });
            }

            ret = Util.stringifyJSON(fileTable);

            return ret;
        }

        this.goToParentDir          = function() {
            var path        = Info.dirPath,
                parentPath  = Info.parentDirPath;

            if (path !== parentPath) {
                path    = parentPath;
                path    = CloudFunc.FS + CloudFunc.rmLastSlash(path);

                CloudCmd.loadDir({
                    path: path
                });
            }
        };

    }
})(this, Util, DOM, CloudFunc);
<|endoftext|>


<commit_before>'use strict';

var request = require('request');

var SERVICE_URL = 'http://188.166.232.247:8007/api';

var SMSClient = {};
var accessToken = null;

/**
 * Autheticate with APIKEY and APISECRET
 */
SMSClient.authenticate = function authenticate(apikey, apisecret, done) {
	if (typeof(done) !== 'function') {
		done = function(err) {
			if (err) {
				console.error(err);
			}
		};
	}
	request({
		method: 'POST',
		url: SERVICE_URL + '/auth',
		headers: {
			apikey: apikey,
			apisecret: apisecret
		}
	},
	function(err, res, body) {
		if (err) {
			return done(err);
		}
		if (res.statusCode === 200) {

			body = JSON.parse(body);
			accessToken = body.access_token;

			done(null);

		} else {
			var httpError = new Error(res.statusCode + ' ' + res.statusMessage);
			httpError.statusCode = res.statusCode;
			httpError.statusMessage = res.statusMessage;
			done(httpError);
		}
	});
};

/**
 * Send SMS message
 */
SMSClient.send = function send(receiver, message, done) {
	if (typeof(done) !== 'function') {
		done = function(err) {
			if (err) {
				console.error(err);
			}
		};
	}
	request({
		method: 'GET',
		url: SERVICE_URL + '/sms',
		headers: {
			Authorization: 'Bearer ' + accessToken
		}
	},
	function(err, res, body) {
		if (err) {
			return done(err);
		}
		if (res.statusCode === 200) {

			body = JSON.parse(body);

			if (body.error) {
				err = new Error(body.errorMessage);
				err.errorCode = body.error;
				return done(err);
			}

			return done(null, body.result);

		} else {
			var httpError = new Error(res.statusCode + ' ' + res.statusMessage);
			httpError.statusCode = res.statusCode;
			httpError.statusMessage = res.statusMessage;
			done(httpError);
		}
	});
};

module.exports = exports = SMSClient;
<commit_msg>Fix #send<commit_after>'use strict';

var request = require('request');

var SERVICE_URL = 'http://188.166.232.247:8007/api';

var SMSClient = {};
var accessToken = null;

/**
 * Autheticate with APIKEY and APISECRET
 */
SMSClient.authenticate = function authenticate(apikey, apisecret, done) {
	if (typeof(done) !== 'function') {
		done = function(err) {
			if (err) {
				console.error(err);
			}
		};
	}
	request({
		method: 'POST',
		url: SERVICE_URL + '/auth',
		headers: {
			apikey: apikey,
			apisecret: apisecret
		}
	},
	function(err, res, body) {
		if (err) {
			return done(err);
		}
		if (res.statusCode === 200) {

			body = JSON.parse(body);
			accessToken = body.access_token;

			done(null);

		} else {
			var httpError = new Error(res.statusCode + ' ' + res.statusMessage);
			httpError.statusCode = res.statusCode;
			httpError.statusMessage = res.statusMessage;
			done(httpError);
		}
	});
};

/**
 * Send SMS message
 */
SMSClient.send = function send(receiver, message, done) {
	if (typeof(done) !== 'function') {
		done = function(err) {
			if (err) {
				console.error(err);
			}
		};
	}
	request({
		method: 'POST',
		url: SERVICE_URL + '/sms',
		headers: {
			Authorization: 'Bearer ' + accessToken
		},
		form: {
			receiver: receiver,
			message: message
		}
	},
	function(err, res, body) {
		if (err) {
			return done(err);
		}
		if (res.statusCode === 200) {

			body = JSON.parse(body);

			if (body.error) {
				err = new Error(body.errorMessage);
				err.errorCode = body.error;
				return done(err);
			}

			return done(null, body.result);

		} else {
			var httpError = new Error(res.statusCode + ' ' + res.statusMessage);
			httpError.statusCode = res.statusCode;
			httpError.statusMessage = res.statusMessage;
			done(httpError);
		}
	});
};

module.exports = exports = SMSClient;
<|endoftext|>


<commit_before>"use strict";
var fs = require('njax-fs');
var path = require('path');
var async = require('async');
var _ = require('underscore');
class NJaxUtil {
	constructor(){
	}
	static module(options, callback) {
		options = options || {};
		var dir = options.dir || path.dirname(module.parent.id);
		var p = new Promise((resolve, reject) => {
			return fs.walkOutUntil(
				dir,
				function (searchDir, next) {
					var searchLoc = path.join(searchDir, 'package.json');

					if (fs.existsSync(searchLoc)) {
						return next(null, true);
					}
					return next(null, false)
				},
				function (err, foundInDir) {
					if (err) return reject(err);
					if (!foundInDir) {
						return resolve();
					}
					return resolve(new NJaxUtil.Module(foundInDir));
				}
			);
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				return reject(e);
			});
		}
		return p;

	}

	static parent(callback) {
		var dir = path.dirname(module.parent.parent.id); //NJaxUtil.getCallerNotInThisModule({ max_hop_count:2});
		var p = NJaxUtil.module({
			dir: dir
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				reject(e);
			});
		}
		return p;
	}

	static get Module() {
		return Module;
	}
	static get Package(){
		return Package;
	}
}
class Package{
	constructor(packageData, packagePath){
		this.packageData = packageData;
		this.path = packagePath;
		Object.keys(this.packageData).forEach((key)=>{
			Object.defineProperty(this, key, {
				get: () =>{
					return this.packageData[key];
				},
				set:(val)=>{
					this.packageData[key];
				}
			});

		})
		_.extend(this, packageData);
	}
	set(key, val){
		this.packageData[key] = val;
	}
	save(){
		return new Promise((resolve, reject)=>{
			return fs.writeJSON(
				this.path,
				this.packageData,
				(err, result) =>{
					console.log(err, result);
					if(err) return reject(err);
					return resolve(result);
				}
			)
		});
	}

}

class Module {
	constructor(root) {
		//console.log('root', root);
		this.root = root;
		return this;
	}
	package(callback) {
		var packagePath = path.join(this.root, 'package.json')
		var p = new Promise((resolve, reject)=> {
			return fs.readJSON(
				packagePath,
				(err, body)=> {
					if (err) return reject(err);
					return resolve(
						new NJaxUtil.Package(
							body,
							packagePath
						));
				}
			);
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				reject(e);
			});
		}
		return p;
	}
}
module.exports = NJaxUtil;<commit_msg>Idk what the diff is here<commit_after>"use strict";
var fs = require('njax-fs');
var path = require('path');
var async = require('async');
var _ = require('underscore');
class NJaxUtil {
	constructor(){
	}
	static module(options, callback) {
		options = options || {};
		var dir = options.dir || path.dirname(module.parent.id);
		var p = new Promise((resolve, reject) => {
			return fs.walkOutUntil(
				dir,
				function (searchDir, next) {
					var searchLoc = path.join(searchDir, 'package.json');

					if (fs.existsSync(searchLoc)) {
						return next(null, true);
					}
					return next (null, false)
				},
				function (err, foundInDir) {
					if (err) return reject(err);
					if (!foundInDir) {
						return resolve();
					}
					return resolve(new NJaxUtil.Module(foundInDir));
				}
			);
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				return reject(e);
			});
		}
		return p;

	}

	static parent(callback) {
		var dir = path.dirname(module.parent.parent.id); //NJaxUtil.getCallerNotInThisModule({ max_hop_count:2});
		var p = NJaxUtil.module({
			dir: dir
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				reject(e);
			});
		}
		return p;
	}

	static get Module() {
		return Module;
	}
	static get Package(){
		return Package;
	}
}
class Package{
	constructor(packageData, packagePath){
		this.packageData = packageData;
		this.path = packagePath;
		Object.keys(this.packageData).forEach((key)=>{
			Object.defineProperty(this, key, {
				get: () =>{
					return this.packageData[key];
				},
				set:(val)=>{
					this.packageData[key];
				}
			});

		})
		_.extend(this, packageData);
	}
	set(key, val){
		this.packageData[key] = val;
	}
	save(){
		return new Promise((resolve, reject)=>{
			return fs.writeJSON(
				this.path,
				this.packageData,
				(err, result) =>{
					console.log(err, result);
					if(err) return reject(err);
					return resolve(result);
				}
			)
		});
	}

}

class Module {
	constructor(root) {
		//console.log('root', root);
		this.root = root;
		return this;
	}
	package(callback) {
		var packagePath = path.join(this.root, 'package.json')
		var p = new Promise((resolve, reject)=> {
			return fs.readJSON(
				packagePath,
				(err, body)=> {
					if (err) return reject(err);
					return resolve(
						new NJaxUtil.Package(
							body,
							packagePath
						));
				}
			);
		});
		if (callback) {
			p.then((result) => {
				return callback(null, result);
			}).catch(e => {
				reject(e);
			});
		}
		return p;
	}
}
module.exports = NJaxUtil;<|endoftext|>


<commit_before>/*
 * QuickBlox JavaScript SDK
 *
 * WebRTC Module
 *
 */

/*
 * User's callbacks (listener-functions):
 * - onCallListener
 * - onAcceptCallListener
 * - onRejectCallListener
 * - onStopCallListener
 * - onRemoteStreamListener
 */

require('../../lib/strophe/strophe.min');
var config = require('../qbConfig'),
    Utils = require('../qbUtils');

// cross-browser polyfill
var RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription;
var RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate;
var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia).bind(navigator);
var URL = window.URL || window.webkitURL;

var signalingType = {
  CALL: 'qbvideochat_call',
  ACCEPT: 'qbvideochat_acceptCall',
  REJECT: 'qbvideochat_rejectCall',
  STOP: 'qbvideochat_stopCall',
  CANDIDATE: 'qbvideochat_candidate',
  PARAMETERS_CHANGED: 'qbvideochat_callParametersChanged'
};

var stopCallReason = {
  MANUALLY: 'kStopVideoChatCallStatus_Manually',
  BAD_CONNECTION: 'kStopVideoChatCallStatus_BadConnection',
  CANCEL: 'kStopVideoChatCallStatus_Cancel',
  NOT_ANSWER: 'kStopVideoChatCallStatus_OpponentDidNotAnswer'
};

var connection, peer;

/* WebRTC module: Core
--------------------------------------------------------------------------------- */
function WebRTCProxy(service, conn) {
  var self = this;
  connection = conn;

  this.service = service;
  this.helpers = new Helpers;

  this._onMessage = function(stanza) {
    var from = stanza.getAttribute('from'),
        extraParams = stanza.querySelector('extraParams'),
        userId = self.helpers.getIdFromNode(from),
        extension = {}, candidates = [], candidate, children, children2;

    if (extraParams) {
      for (var i = 0, len = extraParams.childNodes.length; i < len; i++) {
        if (extraParams.childNodes[i].tagName === 'candidates') {

          // candidates
          children = extraParams.childNodes[i].childNodes;
          for (var j = 0, len2 = children.length; j < len2; j++) {
            candidate = {};
            children2 = children[j].childNodes;
            for (var k = 0, len3 = children2.length; k < len3; k++) {
              candidate[children2[k].tagName] = children2[k].textContent;
            }
            candidates.push(candidate);
          }

        } else {
          extension[extraParams.childNodes[i].tagName] = extraParams.childNodes[i].textContent;
        }
      }

      if (candidates.length > 0)
        extension.candidates = candidates;
    }

    switch (extension.videochat_signaling_type) {
    case signalingType.CALL:
      trace('onCall from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onCallListener === 'function')
        self.onCallListener(userId, extension);
      break;
    case signalingType.ACCEPT:
      trace('onAccept from ' + userId);
      delete extension.videochat_signaling_type;
      peer.onRemoteSessionCallback(extension.sdp, 'answer');
      if (typeof self.onAcceptCallListener === 'function')
        self.onAcceptCallListener(userId, extension);
      break;
    case signalingType.REJECT:
      trace('onReject from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onRejectCallListener === 'function')
        self.onRejectCallListener(userId, extension);
      break;
    case signalingType.STOP:
      trace('onStop from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onStopCallListener === 'function')
        self.onStopCallListener(userId, extension);
      break;
    case signalingType.CANDIDATE:
      peer.addCandidates(extension.candidates);
      if (peer.type === 'answer') {
        self._sendCandidate(peer.opponentId, peer.candidates);
      }
      // peer.addCandidates({
      //   sdpMLineIndex: extension.sdpMLineIndex,
      //   candidate: extension.candidate,
      //   sdpMid: extension.sdpMid
      // });
      break;
    case signalingType.PARAMETERS_CHANGED:
      break;
    }

    // we must return true to keep the handler alive
    // returning false would remove it after it finishes
    return true;
  };
}

/* WebRTC module: User Media Steam
--------------------------------------------------------------------------------- */

// get local stream from user media interface (web-camera, microphone)
WebRTCProxy.prototype.getUserMedia = function(params, callback) {
  if (!getUserMedia) throw new Error('getUserMedia() is not supported in your browser');
  var self = this;

  // Additional parameters for Media Constraints
  // http://tools.ietf.org/html/draft-alvestrand-constraints-resolution-00
  /**********************************************
   * googEchoCancellation: true
   * googAutoGainControl: true
   * googNoiseSuppression: true
   * googHighpassFilter: true
   * minWidth: 640
   * minHeight: 480
   * maxWidth: 1280
   * maxHeight: 720
   * minFrameRate: 60
   * maxAspectRatio: 1.333
  **********************************************/
  getUserMedia(
    params,

    function(stream) {
      self.localStream = stream;
      if (params.elemId)
        self.attachMediaStream(params.elemId, stream, params.options);
      callback(null, stream);
    },

    function(err) {
      callback(err, null);
    }
  );
};

WebRTCProxy.prototype.attachMediaStream = function(id, stream, options) {
  var elem = document.getElementById(id);
  if (elem) {
    elem.src = URL.createObjectURL(stream);
    if (options && options.muted) elem.muted = true;
    if (options && options.mirror) {
      elem.style.webkitTransform = 'scaleX(-1)';
      elem.style.transform = 'scaleX(-1)';
    }
    elem.play();
  }
};

// add CSS filters to video stream
// http://css-tricks.com/almanac/properties/f/filter/
WebRTCProxy.prototype.filter = function(id, filters) {
  var video = document.getElementById(id);
  if (video) {
    video.style.webkitFilter = filters;
    video.style.filter = filters;
  }
};

WebRTCProxy.prototype.snapshot = function(id) {
  var video = document.getElementById(id),
      canvas = document.createElement('canvas'),
      context = canvas.getContext('2d');

  if (video) {
    canvas.width = video.clientWidth;
    canvas.height = video.clientHeight;
    if (video.style.transform === 'scaleX(-1)') {
      context.translate(canvas.width, 0);
      context.scale(-1, 1);
    }
    context.drawImage(video, 0, 0, video.clientWidth, video.clientHeight);

    return canvas.toDataURL('image/png');
  }
};

/* Real-Time Communication (Signaling)
--------------------------------------------------------------------------------- */

WebRTCProxy.prototype.createPeer = function(params) {
  if (!RTCPeerConnection) throw new Error('RTCPeerConnection() is not supported in your browser');
  if (!this.localStream) throw new Error("You don't have an access to the local stream");
  var pcConfig = {
    iceServers: config.iceServers
  };

  // Additional parameters for RTCPeerConnection options
  // new RTCPeerConnection(pcConfig, options)
  /**********************************************
   * DtlsSrtpKeyAgreement: true
   * RtpDataChannels: true
  **********************************************/
  peer = new RTCPeerConnection(pcConfig);
  peer.init(this, params);
  trace('SessionID ' + peer.sessionID);
  trace(peer);
};

WebRTCProxy.prototype.call = function(userId, callType, extension) {
  var self = this;
  peer.opponentId = userId;

  peer.getSessionDescription(function(err, res) {
    if (err) {
      trace(err);
    } else {
      trace('call ' + userId);
      self._sendMessage(userId, extension, 'CALL', callType);
    }
  });
};

WebRTCProxy.prototype.accept = function(userId, extension) {
  var self = this;
  peer.opponentId = userId;

  peer.getSessionDescription(function(err, res) {
    if (err) {
      trace(err);
    } else {
      trace('accept ' + userId);
      self._sendMessage(userId, extension, 'ACCEPT');
    }
  });
};

WebRTCProxy.prototype.reject = function(userId, extension) {
  trace('reject ' + userId);
  this._sendMessage(userId, extension, 'REJECT');
};

WebRTCProxy.prototype.stop = function(userId, reason, extension) {
  trace('stop ' + userId);
  var extension = extension || {},
      status = reason || 'manually';

  extension.status = stopCallReason[status.toUpperCase()];
  this._sendMessage(userId, extension, 'STOP');
};

WebRTCProxy.prototype.hangup = function() {
  this.localStream.stop();
  peer.close();
};

WebRTCProxy.prototype._sendCandidate = function(userId, candidates) {
  var extension = {
    candidates: candidates
  };
  // var extension = {
  //   sdpMLineIndex: candidate.sdpMLineIndex,
  //   candidate: candidate.candidate,
  //   sdpMid: candidate.sdpMid
  // };

  this._sendMessage(userId, extension, 'CANDIDATE');
};

WebRTCProxy.prototype._sendMessage = function(userId, extension, type, callType) {
  var extension = extension || {},
      self = this,
      msg, params;

  extension.videochat_signaling_type = signalingType[type];
  extension.sessionID = peer && peer.sessionID || extension.sessionID;

  if (type === 'CALL' || type === 'ACCEPT') {
    if (callType) extension.callType = callType === 'video' ? 1 : 2;
    extension.sdp = peer.localDescription.sdp;
    extension.platform = 'web';
    extension.device_orientation = 'portrait';
  }

  params = {
    from: connection.jid,
    to: self.helpers.getUserJid(userId, self.service.getSession().application_id),
    type: 'headline',
    id: Utils.getBsonObjectId()
  };

  msg = $msg(params).c('extraParams', {
    xmlns: Strophe.NS.CLIENT
  });

  Object.keys(extension).forEach(function(field) {
    if (field === 'candidates') {

      // candidates
      msg = msg.c('candidates');
      extension[field].forEach(function(candidate) {
        msg = msg.c('candidate');
        Object.keys(candidate).forEach(function(key) {
          msg.c(key).t(candidate[key]).up();
        });
        msg.up();
      });
      msg.up();

    } else {
      msg.c(field).t(extension[field]).up();
    }
  });

  connection.send(msg);
};

/* RTCPeerConnection extension
--------------------------------------------------------------------------------- */

RTCPeerConnection.prototype.init = function(service, options) {
  this.service = service;
  this.sessionID = parseInt(options && options.sessionID) || Date.now();
  this.type = options && options.description ? 'answer' : 'offer';
  this.addStream(this.service.localStream);

  if (this.type === 'answer') {
    this.onRemoteSessionCallback(options.description, 'offer');
  }

  this.onicecandidate = this.onIceCandidateCallback;
  this.onaddstream = this.onRemoteStreamCallback;

  this.oniceconnectionstatechange = function() {
    if (peer.iceConnectionState === 'closed' || peer.iceConnectionState === 'disconnected')
      peer = null;
  };
  this.onsignalingstatechange = function() {
    // send candidates
    if (peer && peer.signalingState === 'stable' && peer.type === 'offer') {
      peer.service._sendCandidate(peer.opponentId, peer.candidates);
    }

    // if (peer.signalingState === 'stable' && peer.candidates && peer.candidates.length > 0) {
    //   for (var i = 0, len = peer.candidates.length; i < len; i++) {
    //     candidate = peer.candidates.pop();
    //     peer.service._sendCandidate(peer.opponentId, candidate);
    //   }
    // }
  };
};

RTCPeerConnection.prototype.getSessionDescription = function(callback) {
  var request = (peer.type === 'offer' ? peer.createOffer : peer.createAnswer).bind(peer);

  // Additional parameters for SDP Constraints
  // http://www.w3.org/TR/webrtc/#constraints
  // peer.createOffer(successCallback, errorCallback, constraints)
  request(
    function(desc) {
      peer.setLocalDescription(desc, function() {
        callback(null, desc);
      });
    },

    function(error) {
      callback(error, null);
    }
  );
}

RTCPeerConnection.prototype.onRemoteSessionCallback = function(sessionDescription, type) {
  var desc = new RTCSessionDescription({sdp: sessionDescription, type: type});
  peer.setRemoteDescription(desc);
};

RTCPeerConnection.prototype.onIceCandidateCallback = function(event) {
  var candidate = event.candidate;

  if (candidate) {
    peer.candidates = peer.candidates || [];
    peer.candidates.push({
      sdpMLineIndex: candidate.sdpMLineIndex,
      sdpMid: candidate.sdpMid,
      sdp: candidate.candidate
    });
    // if (peer.signalingState === 'stable') {
    //   peer.service._sendCandidate(peer.opponentId, candidate);
    // } else {
    //   peer.candidates = peer.candidates || [];
    //   peer.candidates.push(candidate);
    // }
  }
};

RTCPeerConnection.prototype.addCandidates = function(candidates) {
  var candidate;

  for (var i = 0, len = candidates.length; i < len; i++) {
    candidate = {
      sdpMLineIndex: candidates[i].sdpMLineIndex,
      sdpMid: candidates[i].sdpMid,
      candidate: candidates[i].sdp
    };
    peer.addIceCandidate(new RTCIceCandidate(candidate));
  }
  // candidate = new RTCIceCandidate(data);
  // peer.addIceCandidate(candidate);
};

RTCPeerConnection.prototype.onRemoteStreamCallback = function(event) {
  if (typeof peer.service.onRemoteStreamListener === 'function')
    peer.service.onRemoteStreamListener(event.stream);
};

/* Helpers
---------------------------------------------------------------------- */
function Helpers() {}

Helpers.prototype = {

  getUserJid: function(id, appId) {
    return id + '-' + appId + '@' + config.endpoints.chat;
  },

  getIdFromNode: function(jid) {
    if (jid.indexOf('@') < 0) return null;
    return parseInt(jid.split('@')[0].split('-')[0]);
  }

};

module.exports = WebRTCProxy;

/* Private
---------------------------------------------------------------------- */
function trace(text) {
  // if (config.debug) {
    console.log('[QBWebRTC]:', text);
  // }
}
<commit_msg>mute/unmute devices<commit_after>/*
 * QuickBlox JavaScript SDK
 *
 * WebRTC Module
 *
 */

/*
 * User's callbacks (listener-functions):
 * - onCallListener
 * - onAcceptCallListener
 * - onRejectCallListener
 * - onStopCallListener
 * - onRemoteStreamListener
 */

require('../../lib/strophe/strophe.min');
var config = require('../qbConfig'),
    Utils = require('../qbUtils');

// cross-browser polyfill
var RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection || window.mozRTCPeerConnection;
var RTCSessionDescription = window.RTCSessionDescription || window.mozRTCSessionDescription;
var RTCIceCandidate = window.RTCIceCandidate || window.mozRTCIceCandidate;
var getUserMedia = (navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia).bind(navigator);
var URL = window.URL || window.webkitURL;

var signalingType = {
  CALL: 'qbvideochat_call',
  ACCEPT: 'qbvideochat_acceptCall',
  REJECT: 'qbvideochat_rejectCall',
  STOP: 'qbvideochat_stopCall',
  CANDIDATE: 'qbvideochat_candidate',
  PARAMETERS_CHANGED: 'qbvideochat_callParametersChanged'
};

var stopCallReason = {
  MANUALLY: 'kStopVideoChatCallStatus_Manually',
  BAD_CONNECTION: 'kStopVideoChatCallStatus_BadConnection',
  CANCEL: 'kStopVideoChatCallStatus_Cancel',
  NOT_ANSWER: 'kStopVideoChatCallStatus_OpponentDidNotAnswer'
};

var connection, peer;

/* WebRTC module: Core
--------------------------------------------------------------------------------- */
function WebRTCProxy(service, conn) {
  var self = this;
  connection = conn;

  this.service = service;
  this.helpers = new Helpers;

  this._onMessage = function(stanza) {
    var from = stanza.getAttribute('from'),
        extraParams = stanza.querySelector('extraParams'),
        userId = self.helpers.getIdFromNode(from),
        extension = {}, candidates = [], candidate, children, children2;

    if (extraParams) {
      for (var i = 0, len = extraParams.childNodes.length; i < len; i++) {
        if (extraParams.childNodes[i].tagName === 'candidates') {

          // candidates
          children = extraParams.childNodes[i].childNodes;
          for (var j = 0, len2 = children.length; j < len2; j++) {
            candidate = {};
            children2 = children[j].childNodes;
            for (var k = 0, len3 = children2.length; k < len3; k++) {
              candidate[children2[k].tagName] = children2[k].textContent;
            }
            candidates.push(candidate);
          }

        } else {
          extension[extraParams.childNodes[i].tagName] = extraParams.childNodes[i].textContent;
        }
      }

      if (candidates.length > 0)
        extension.candidates = candidates;
    }

    switch (extension.videochat_signaling_type) {
    case signalingType.CALL:
      trace('onCall from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onCallListener === 'function')
        self.onCallListener(userId, extension);
      break;
    case signalingType.ACCEPT:
      trace('onAccept from ' + userId);
      delete extension.videochat_signaling_type;
      peer.onRemoteSessionCallback(extension.sdp, 'answer');
      if (typeof self.onAcceptCallListener === 'function')
        self.onAcceptCallListener(userId, extension);
      break;
    case signalingType.REJECT:
      trace('onReject from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onRejectCallListener === 'function')
        self.onRejectCallListener(userId, extension);
      break;
    case signalingType.STOP:
      trace('onStop from ' + userId);
      delete extension.videochat_signaling_type;
      if (typeof self.onStopCallListener === 'function')
        self.onStopCallListener(userId, extension);
      break;
    case signalingType.CANDIDATE:
      peer.addCandidates(extension.candidates);
      if (peer.type === 'answer') {
        self._sendCandidate(peer.opponentId, peer.candidates);
      }
      // peer.addCandidates({
      //   sdpMLineIndex: extension.sdpMLineIndex,
      //   candidate: extension.candidate,
      //   sdpMid: extension.sdpMid
      // });
      break;
    case signalingType.PARAMETERS_CHANGED:
      break;
    }

    // we must return true to keep the handler alive
    // returning false would remove it after it finishes
    return true;
  };
}

/* WebRTC module: User Media Steam
--------------------------------------------------------------------------------- */

// get local stream from user media interface (web-camera, microphone)
WebRTCProxy.prototype.getUserMedia = function(params, callback) {
  if (!getUserMedia) throw new Error('getUserMedia() is not supported in your browser');
  var self = this;

  // Additional parameters for Media Constraints
  // http://tools.ietf.org/html/draft-alvestrand-constraints-resolution-00
  /**********************************************
   * googEchoCancellation: true
   * googAutoGainControl: true
   * googNoiseSuppression: true
   * googHighpassFilter: true
   * minWidth: 640
   * minHeight: 480
   * maxWidth: 1280
   * maxHeight: 720
   * minFrameRate: 60
   * maxAspectRatio: 1.333
  **********************************************/
  getUserMedia(
    params,

    function(stream) {
      self.localStream = stream;
      if (params.elemId)
        self.attachMediaStream(params.elemId, stream, params.options);
      callback(null, stream);
    },

    function(err) {
      callback(err, null);
    }
  );
};

WebRTCProxy.prototype.attachMediaStream = function(id, stream, options) {
  var elem = document.getElementById(id);
  if (elem) {
    elem.src = URL.createObjectURL(stream);
    if (options && options.muted) elem.muted = true;
    if (options && options.mirror) {
      elem.style.webkitTransform = 'scaleX(-1)';
      elem.style.transform = 'scaleX(-1)';
    }
    elem.play();
  }
};

// add CSS filters to video stream
// http://css-tricks.com/almanac/properties/f/filter/
WebRTCProxy.prototype.filter = function(id, filters) {
  var video = document.getElementById(id);
  if (video) {
    video.style.webkitFilter = filters;
    video.style.filter = filters;
  }
};

WebRTCProxy.prototype.snapshot = function(id) {
  var video = document.getElementById(id),
      canvas = document.createElement('canvas'),
      context = canvas.getContext('2d');

  if (video) {
    canvas.width = video.clientWidth;
    canvas.height = video.clientHeight;
    if (video.style.transform === 'scaleX(-1)') {
      context.translate(canvas.width, 0);
      context.scale(-1, 1);
    }
    context.drawImage(video, 0, 0, video.clientWidth, video.clientHeight);

    return canvas.toDataURL('image/png');
  }
};

WebRTCProxy.prototype.mute = function(type) {
  this._switchOffDevice(0, type);
};

WebRTCProxy.prototype.unmute = function(type) {
  this._switchOffDevice(1, type);
};

WebRTCProxy.prototype._switchOffDevice = function(bool, type) {
  if (type === 'audio') {
    this.localStream.getAudioTracks().forEach(function (track) {
      track.enabled = !!bool;
    });
  }
  if (type === 'video') {
    this.localStream.getVideoTracks().forEach(function (track) {
      track.enabled = !!bool;
    });
  }
};

/* Real-Time Communication (Signaling)
--------------------------------------------------------------------------------- */

WebRTCProxy.prototype.createPeer = function(params) {
  if (!RTCPeerConnection) throw new Error('RTCPeerConnection() is not supported in your browser');
  if (!this.localStream) throw new Error("You don't have an access to the local stream");
  var pcConfig = {
    iceServers: config.iceServers
  };

  // Additional parameters for RTCPeerConnection options
  // new RTCPeerConnection(pcConfig, options)
  /**********************************************
   * DtlsSrtpKeyAgreement: true
   * RtpDataChannels: true
  **********************************************/
  peer = new RTCPeerConnection(pcConfig);
  peer.init(this, params);
  trace('SessionID ' + peer.sessionID);
  trace(peer);
};

WebRTCProxy.prototype.call = function(userId, callType, extension) {
  var self = this;
  peer.opponentId = userId;

  peer.getSessionDescription(function(err, res) {
    if (err) {
      trace(err);
    } else {
      trace('call ' + userId);
      self._sendMessage(userId, extension, 'CALL', callType);
    }
  });
};

WebRTCProxy.prototype.accept = function(userId, extension) {
  var self = this;
  peer.opponentId = userId;

  peer.getSessionDescription(function(err, res) {
    if (err) {
      trace(err);
    } else {
      trace('accept ' + userId);
      self._sendMessage(userId, extension, 'ACCEPT');
    }
  });
};

WebRTCProxy.prototype.reject = function(userId, extension) {
  trace('reject ' + userId);
  this._sendMessage(userId, extension, 'REJECT');
};

WebRTCProxy.prototype.stop = function(userId, reason, extension) {
  trace('stop ' + userId);
  var extension = extension || {},
      status = reason || 'manually';

  extension.status = stopCallReason[status.toUpperCase()];
  this._sendMessage(userId, extension, 'STOP');
};

WebRTCProxy.prototype.hangup = function() {
  this.localStream.stop();
  peer.close();
};

WebRTCProxy.prototype._sendCandidate = function(userId, candidates) {
  var extension = {
    candidates: candidates
  };
  // var extension = {
  //   sdpMLineIndex: candidate.sdpMLineIndex,
  //   candidate: candidate.candidate,
  //   sdpMid: candidate.sdpMid
  // };

  this._sendMessage(userId, extension, 'CANDIDATE');
};

WebRTCProxy.prototype._sendMessage = function(userId, extension, type, callType) {
  var extension = extension || {},
      self = this,
      msg, params;

  extension.videochat_signaling_type = signalingType[type];
  extension.sessionID = peer && peer.sessionID || extension.sessionID;

  if (type === 'CALL' || type === 'ACCEPT') {
    if (callType) extension.callType = callType === 'video' ? 1 : 2;
    extension.sdp = peer.localDescription.sdp;
    extension.platform = 'web';
    extension.device_orientation = 'portrait';
  }

  params = {
    from: connection.jid,
    to: self.helpers.getUserJid(userId, self.service.getSession().application_id),
    type: 'headline',
    id: Utils.getBsonObjectId()
  };

  msg = $msg(params).c('extraParams', {
    xmlns: Strophe.NS.CLIENT
  });

  Object.keys(extension).forEach(function(field) {
    if (field === 'candidates') {

      // candidates
      msg = msg.c('candidates');
      extension[field].forEach(function(candidate) {
        msg = msg.c('candidate');
        Object.keys(candidate).forEach(function(key) {
          msg.c(key).t(candidate[key]).up();
        });
        msg.up();
      });
      msg.up();

    } else {
      msg.c(field).t(extension[field]).up();
    }
  });

  connection.send(msg);
};

/* RTCPeerConnection extension
--------------------------------------------------------------------------------- */

RTCPeerConnection.prototype.init = function(service, options) {
  this.service = service;
  this.sessionID = parseInt(options && options.sessionID) || Date.now();
  this.type = options && options.description ? 'answer' : 'offer';
  this.addStream(this.service.localStream);

  if (this.type === 'answer') {
    this.onRemoteSessionCallback(options.description, 'offer');
  }

  this.onicecandidate = this.onIceCandidateCallback;
  this.onaddstream = this.onRemoteStreamCallback;

  this.oniceconnectionstatechange = function() {
    if (peer.iceConnectionState === 'closed' || peer.iceConnectionState === 'disconnected')
      peer = null;
  };
  this.onsignalingstatechange = function() {
    // send candidates
    if (peer && peer.signalingState === 'stable' && peer.type === 'offer') {
      peer.service._sendCandidate(peer.opponentId, peer.candidates);
    }

    // if (peer.signalingState === 'stable' && peer.candidates && peer.candidates.length > 0) {
    //   for (var i = 0, len = peer.candidates.length; i < len; i++) {
    //     candidate = peer.candidates.pop();
    //     peer.service._sendCandidate(peer.opponentId, candidate);
    //   }
    // }
  };
};

RTCPeerConnection.prototype.getSessionDescription = function(callback) {
  var request = (peer.type === 'offer' ? peer.createOffer : peer.createAnswer).bind(peer);

  // Additional parameters for SDP Constraints
  // http://www.w3.org/TR/webrtc/#constraints
  // peer.createOffer(successCallback, errorCallback, constraints)
  request(
    function(desc) {
      peer.setLocalDescription(desc, function() {
        callback(null, desc);
      });
    },

    function(error) {
      callback(error, null);
    }
  );
}

RTCPeerConnection.prototype.onRemoteSessionCallback = function(sessionDescription, type) {
  var desc = new RTCSessionDescription({sdp: sessionDescription, type: type});
  peer.setRemoteDescription(desc);
};

RTCPeerConnection.prototype.onIceCandidateCallback = function(event) {
  var candidate = event.candidate;

  if (candidate) {
    peer.candidates = peer.candidates || [];
    peer.candidates.push({
      sdpMLineIndex: candidate.sdpMLineIndex,
      sdpMid: candidate.sdpMid,
      sdp: candidate.candidate
    });
    // if (peer.signalingState === 'stable') {
    //   peer.service._sendCandidate(peer.opponentId, candidate);
    // } else {
    //   peer.candidates = peer.candidates || [];
    //   peer.candidates.push(candidate);
    // }
  }
};

RTCPeerConnection.prototype.addCandidates = function(candidates) {
  var candidate;

  for (var i = 0, len = candidates.length; i < len; i++) {
    candidate = {
      sdpMLineIndex: candidates[i].sdpMLineIndex,
      sdpMid: candidates[i].sdpMid,
      candidate: candidates[i].sdp
    };
    peer.addIceCandidate(new RTCIceCandidate(candidate));
  }
  // candidate = new RTCIceCandidate(data);
  // peer.addIceCandidate(candidate);
};

RTCPeerConnection.prototype.onRemoteStreamCallback = function(event) {
  if (typeof peer.service.onRemoteStreamListener === 'function')
    peer.service.onRemoteStreamListener(event.stream);
};

/* Helpers
---------------------------------------------------------------------- */
function Helpers() {}

Helpers.prototype = {

  getUserJid: function(id, appId) {
    return id + '-' + appId + '@' + config.endpoints.chat;
  },

  getIdFromNode: function(jid) {
    if (jid.indexOf('@') < 0) return null;
    return parseInt(jid.split('@')[0].split('-')[0]);
  }

};

module.exports = WebRTCProxy;

/* Private
---------------------------------------------------------------------- */
function trace(text) {
  // if (config.debug) {
    console.log('[QBWebRTC]:', text);
  // }
}
<|endoftext|>