<commit_before>
var fs = require('fs');
var exec = require ('child_process').exec;
var async = require ("async");
var app_path, ssh_file, local, email;
var i = 0;
var prompt = require ("prompt");
var config = {};

async.waterfall ([

    function (done){
        // Installs the whole setup
        console.log ("\n\nWELCOME TO THE NODE-AWS-DEPLOY INSTALLER");
        console.log ("This installs your application onto AWS and allows automatic deployment just by pushing to your remote git repository." +
            " Just answer a few questions and everything will be setup");
        prompt.start ();
        done ();
    }/*,

    function (done){
        console.log (++i + ") Is this a 'remote' install? (If this is on a remote server the answer is y)");
        prompt.get (['(y/n)'], function (err, results){
            var answer = (results['(y/n)'] === 'y');
            local = !answer;
            config.sudo = (local) ? "" : "sudo";
            done ();
        });
    },

    function (done){
        if (local){
            console.log (++i + ") Enter your desired application's full path. (no file names. Example  '/User/me/MyCoolApplication')");
            prompt.get (['folder'], function (err, results){
                config.applicationDirectory = results['folder'];
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        console.log (++i + ") Enter your application's name");
        prompt.get (['name'], function (err, results){
            config.applicationName = results['name'];
            done ();
        });
    },

    function (done){
        console.log (++i + ") Enter your application's entry point (defaults to 'start.js')");
        prompt.get (['entry point'], function(err, results) {
            config.appEntry = results['entry point'];
            done ();
        });
    },
    function (done){
        if (local){
            console.log ("Please take a second ensure you are set up to clone your repository. This might require you to create an ssh key pair or simply use credentials.");
            console.log ("When you have your repository cloned press <enter> to continue.");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            // go get the ssh key
            try { ssh_file = fs.readFileSync ("/root/.ssh/id_rsa.pub");}
            catch (err) {ssh_file = null;}
            if (!ssh_file){
                done ("/tssh key not generated, please exit generate one, and re-run");
            }
            else{
                done ();
            }
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log(++i + ") Please take a second to copy the ssh key from this server, listed below, and paste into your git repository service (such as github). This will authorize this server AMI to " +
                "clone your repository and perform git pulls. Press <enter> when done.");
            console.log ("\n" + ssh_file + "\n");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Now that your Git repository has been configured, enter the ssh url for remote access so this server can clone it:");
            prompt.get (['Git repository URL'], function (err, results){
                var git_url = results['Git repository URL'];
                if (git_url){
                    console.log ("  Cloning your repository...");
                    var child = exec ('cd ' + config.applicationDirectory + ' ; cd .. ; ' + config.sudo + ' git clone ' + git_url, function (err, std, ster){
                        if (err){
                            done (err);
                        }
                        else{
                            console.log (std);
                            var dir = std.split ("Cloning into ");
                            // extract the directory from the git clone string
                            dir = dir && dir[1] && dir[1].split ("'")[1].replace ("...", "");
                            if (dir){
                                config.applicationDirectory = '/home/ec2-user/' + dir;
                            }
                            done ();
                        }
                    });
                }
                else{
                    done ();
                }
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log (++i + ") Enter the pull information, what triggers it how its configured, etc...");
            console.log ("\t pullPort: <set this to the port for a pull requests> - defaults to 8000");
            console.log ("\t pullKey: <path to a ssh key file for the HTTPS Server>");
            console.log ("\t pullCert: <path to a ssh cert file for the HTTPS Server>");
            console.log ("\t pullCa: <array of paths to the certificate authority files> (optional)");
            console.log ("\t pullPassphrase: <string - phrase that the certificate was generated with> (optional)");
            console.log ("\t pullSecret: <secret phrase that this server uses to identify as a valid pull request> (optional))");
            console.log ("\t pullBranch: <the branch that this server should pull from on pull requests> (defaults to master))");
            prompt.get (["pullPort", "pullKey", "pullCert", "pullCa", "pullPassphrase", "pullSecret", "pullBranch"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    },
    function (done) {
        if (!local){
            console.log (++i + ") Enter AWS SDK Information so that this server can talk to others on a pull request");
            console.log ("\t accessKeyId: <AWS API Access key 'XXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t secretAccessKey: <AWS Secret Access key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t region: <aws region that the servers are located in. EX 'us-east-1'>");
            prompt.get (["accessKeyId", "secretAccessKey", "region"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    }*/

], function (err){
    if (!err){
        var data = JSON.stringify (config);
        fs.writeFileSync (config.applicationDirectory + "/.app-config.json", data);
        console.log ("Success installed: " + config.applicationName + ". The Configuration has been written out to app-config.json");
        if (!local){
            console.log ("To Launch the application type 'sudo start " + (config.applicationName || "node-aws-deploy") + "'");
            // rename the upstart file to the applicaiton name
            if (config.applicationName){
                var name = config.applicationName + ".conf";
console.log (name);
                var child = exec ("sudo mv /etc/init/node-aws-deploy.conf /etc/init/" + name, function (err, std, ster){
                    var data = fs.readFileSync ('/etc/init/' + name);
console.log (data);

                    var data_str = data && data.toString ();
                    if (data_str && data_str.replace){
                        data_str && data_str.replace ('PLACE_HOLDER', config.applicationDirectory);
console.log (data_str);
                        fs.writeFileSync ('/etc/init/' + name, data_str);
                    }
                    process.exit (0);
                });
            }
            else{
                process.exit (0);
            }
        }
        else{
            process.exit (0);
        }
    }
    else{
        console.log ("There were errors. Errors:" + err);
        process.exit (1);
    }
});

<commit_msg>Initial<commit_after>
var fs = require('fs');
var exec = require ('child_process').exec;
var async = require ("async");
var app_path, ssh_file, local, email;
var i = 0;
var prompt = require ("prompt");
var config = {};

async.waterfall ([

    function (done){
        // Installs the whole setup
        console.log ("\n\nWELCOME TO THE NODE-AWS-DEPLOY INSTALLER");
        console.log ("This installs your application onto AWS and allows automatic deployment just by pushing to your remote git repository." +
            " Just answer a few questions and everything will be setup");
        prompt.start ();
        done ();
    }/*,

    function (done){
        console.log (++i + ") Is this a 'remote' install? (If this is on a remote server the answer is y)");
        prompt.get (['(y/n)'], function (err, results){
            var answer = (results['(y/n)'] === 'y');
            local = !answer;
            config.sudo = (local) ? "" : "sudo";
            done ();
        });
    },

    function (done){
        if (local){
            console.log (++i + ") Enter your desired application's full path. (no file names. Example  '/User/me/MyCoolApplication')");
            prompt.get (['folder'], function (err, results){
                config.applicationDirectory = results['folder'];
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        console.log (++i + ") Enter your application's name");
        prompt.get (['name'], function (err, results){
            config.applicationName = results['name'];
            done ();
        });
    },

    function (done){
        console.log (++i + ") Enter your application's entry point (defaults to 'start.js')");
        prompt.get (['entry point'], function(err, results) {
            config.appEntry = results['entry point'];
            done ();
        });
    },
    function (done){
        if (local){
            console.log ("Please take a second ensure you are set up to clone your repository. This might require you to create an ssh key pair or simply use credentials.");
            console.log ("When you have your repository cloned press <enter> to continue.");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            // go get the ssh key
            try { ssh_file = fs.readFileSync ("/root/.ssh/id_rsa.pub");}
            catch (err) {ssh_file = null;}
            if (!ssh_file){
                done ("/tssh key not generated, please exit generate one, and re-run");
            }
            else{
                done ();
            }
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log(++i + ") Please take a second to copy the ssh key from this server, listed below, and paste into your git repository service (such as github). This will authorize this server AMI to " +
                "clone your repository and perform git pulls. Press <enter> when done.");
            console.log ("\n" + ssh_file + "\n");
            prompt.get (['<enter>'], function(err, results) {
                done ();
            });
        }
        else{
            done ();
        }
    },
    function (done){
        if (!local){
            console.log (++i + ") Now that your Git repository has been configured, enter the ssh url for remote access so this server can clone it:");
            prompt.get (['Git repository URL'], function (err, results){
                var git_url = results['Git repository URL'];
                if (git_url){
                    console.log ("  Cloning your repository...");
                    var child = exec ('cd ' + config.applicationDirectory + ' ; cd .. ; ' + config.sudo + ' git clone ' + git_url, function (err, std, ster){
                        if (err){
                            done (err);
                        }
                        else{
                            console.log (std);
                            var dir = std.split ("Cloning into ");
                            // extract the directory from the git clone string
                            dir = dir && dir[1] && dir[1].split ("'")[1].replace ("...", "");
                            if (dir){
                                config.applicationDirectory = '/home/ec2-user/' + dir;
                            }
                            done ();
                        }
                    });
                }
                else{
                    done ();
                }
            });
        }
        else{
            done ();
        }
    },

    function (done){
        if (!local){
            console.log (++i + ") Enter the pull information, what triggers it how its configured, etc...");
            console.log ("\t pullPort: <set this to the port for a pull requests> - defaults to 8000");
            console.log ("\t pullKey: <path to a ssh key file for the HTTPS Server>");
            console.log ("\t pullCert: <path to a ssh cert file for the HTTPS Server>");
            console.log ("\t pullCa: <array of paths to the certificate authority files> (optional)");
            console.log ("\t pullPassphrase: <string - phrase that the certificate was generated with> (optional)");
            console.log ("\t pullSecret: <secret phrase that this server uses to identify as a valid pull request> (optional))");
            console.log ("\t pullBranch: <the branch that this server should pull from on pull requests> (defaults to master))");
            prompt.get (["pullPort", "pullKey", "pullCert", "pullCa", "pullPassphrase", "pullSecret", "pullBranch"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    },
    function (done) {
        if (!local){
            console.log (++i + ") Enter AWS SDK Information so that this server can talk to others on a pull request");
            console.log ("\t accessKeyId: <AWS API Access key 'XXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t secretAccessKey: <AWS Secret Access key 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'>");
            console.log ("\t region: <aws region that the servers are located in. EX 'us-east-1'>");
            prompt.get (["accessKeyId", "secretAccessKey", "region"], function (err, results){
                for (var k in results){
                    config[k] = results[k];
                }
                done ();
            });

        }
        else{
            done ();
        }
    }*/

], function (err){
    if (!err){
config.applicationDirectory = "/home/ec2-user/ABoxAbove";
config.applicationName = "aba";
        var data = JSON.stringify (config);
        fs.writeFileSync (config.applicationDirectory + "/.app-config.json", data);
        console.log ("Success installed: " + config.applicationName + ". The Configuration has been written out to app-config.json");
        if (!local){
            console.log ("To Launch the application type 'sudo start " + (config.applicationName || "node-aws-deploy") + "'");
            // rename the upstart file to the applicaiton name
            if (config.applicationName){
                var name = config.applicationName + ".conf";
console.log (name);
                var child = exec ("sudo mv /etc/init/node-aws-deploy.conf /etc/init/" + name, function (err, std, ster){
                    var data = fs.readFileSync ('/etc/init/' + name);
console.log (data);

                    var data_str = data && data.toString ();
                    if (data_str && data_str.replace){
                        data_str && data_str.replace ('PLACE_HOLDER', config.applicationDirectory);
console.log (data_str);
                        fs.writeFileSync ('/etc/init/' + name, data_str);
                    }
                    process.exit (0);
                });
            }
            else{
                process.exit (0);
            }
        }
        else{
            process.exit (0);
        }
    }
    else{
        console.log ("There were errors. Errors:" + err);
        process.exit (1);
    }
});

<|endoftext|>


<commit_before>var ChatServerActionCreators = require('../actions/ChatServerActionCreators');
var XMPP = require('./xmpp.js');
var ChatMessageUtils = require('./ChatMessageUtils');
var urlUtils = require('./urlUtils');
import UserProfileStore from '../stores/UserProfileStore';
import { get } from '../../../js/request';

var _connection, // raw connection
    _connectResolve,
    _connectionStatus, _domain, _me, _myJID, _nick;
var _pendingFriends = [];

// TODO I think this state is maybe in the wrong place
// E.g. if we have a ContactStore, it would request history and profile
// to be fetched when a contact is first added?
var historyLoadedFor = [];
var userProfileLoadedFor = [];
//

var sentIsTyping = {};

// Strophe.log = function (level, msg) {
//     console.log(msg);
// };

var connect = new Promise((resolve, reject) => {
    _connectResolve = resolve;
});

function onConnectFactory (resolve) {
    return function (status_code) {
        _connectionStatus = status_code;
        if (status_code == Strophe.Status.CONNECTED) {
            sendInitialPresence();
	    addPrivateChatHandlers();
            _connection.mam.init(_connection);
            _connection.addHandler(
                receiveArchivedPrivateMessage, Strophe.NS.MAM, "message", null);
            getContacts();
            loadUserProfile(Strophe.getNodeFromJid(_myJID));
            _connection.chatstates.init(_connection);
            if (chatConf.hasChatroom) {
                _connection.muc.init(_connection);
	      addGroupChatHandlers();
            }
            if (_pendingFriends.length) {
                _pendingFriends.forEach(f => addFriend(f));
            }
            resolve(_connection);
            ChatServerActionCreators.connect(_connection);
        } else if (status_code == Strophe.Status.DISCONNECTED) {
            ChatServerActionCreators.disconnect();
        }
    }
};

function sendInitialPresence () {
    _connection.send($pres().tree());
}

var getChatrooms = new Promise((resolve, reject) => {
    // TODO not sure here about using a promise inside a promise
    // TODO fix this hack to workaround problems joining the main chatroom
    // when viewing private messages. For now we don't join the chatroom
    // as private and group threads are intermingled in the thread store
    // and that breaks thinsgs.
    if (window.location.href.indexOf('messages') === -1 &&
        window.location.href.indexOf('sessions') === -1) {
        connect.then(connection => {
            var chatDomain = 'muc.' + _domain; // TODO pass in from config
            connection.muc.listRooms(
                chatDomain,
                receiveChatrooms(resolve),
                reject
            )
        });
    }
});

// TODO is there a better pattern to use here?
// Want getChatrooms to be a promise but want .then funcs to receive the parsed roomList
// not the raw XMPP result. Seems I'm going to be writing a lot of factory functions to
// return functions that call `resolve`...
function receiveChatrooms (resolve) {
    return function (result) {
//        console.log('got chatrooms');
        var roomList = XMPP.parse.roomList(result);
        resolve(roomList);
	ChatServerActionCreators.receiveChatrooms(roomList);
    }
};

getChatrooms.then(roomList => {
    if (roomList.length) {
	// TODO something better than these path inspection hacks, pass some explicit option?
	if (window.location.href.indexOf('chatroom') === -1) {
            // Anywhere outside of /chatrooms/ we just want to join the 'main' site chatroom
          let mainRoom = roomList.find(r => r.startsWith('main'));
//          console.log('joining', mainRoom);
          joinChatroom(mainRoom);
	}
    }
});

function joinChatroom (roomJID) {
    if (!chatConf.hasChatroom) {
        return;
    }
    Promise.all([
        connect,  // TODO not sure this is need as getChatrooms already depends on it
        getChatrooms
    ]).then(result => {
        var [connection, roomList] = result;
        if (roomList.indexOf(roomJID) === -1) {
//            console.log('No such room', roomList);
            return;
        }
        // TODO this isn't quite the right place, should probably do
        // when get presence back confirming room join
        ChatServerActionCreators.joinChatroom(roomJID);
        connection.muc.join(
            roomJID,
            _nick
        );
    });
}

function receiveGroupMessage (msg) {
    var message = XMPP.parse.groupMessage(msg);
    // TODO not sure about treating a group message as just another message. Makes some sense, as it's just another thread
    message.threadID = message.to;
    message.authorName = message.from;
    if (message.from) {
	// TODO always get an 'empty' message from the room
	// itself, not sure why
      ChatServerActionCreators.receivePrivateMessage(message, true);
    }
    return true;
};

function receiveGroupPresence (pres) {
    var presence = XMPP.parse.groupPresence(pres);
    if (presence.added) {
      ChatServerActionCreators.receiveOnline(presence.user, presence.room);
      loadUserProfile(presence.user);
    } else if (presence.removed) {
        ChatServerActionCreators.receiveOffline(presence.user, presence.room);
        if (presence.destroyed) {
            ChatServerActionCreators.leaveChatroom(presence.room);
        }
    }
    // TODO ChatServerActionCreators.joinChatroom
    return true;
}

function addPrivateChatHandlers () {
    _connection.addHandler(receivePrivateMessage, null, 'message', 'chat',  null);
    _connection.addHandler(receivePresence, null, 'presence', null,  null);
}

function addGroupChatHandlers() {
  _connection.addHandler(receiveGroupMessage, null, 'message', 'groupchat', null);
  _connection.addHandler(receiveGroupPresence, null, 'presence', null, null);
}

function getContacts () {
    _connection.roster.init(_connection);
    _connection.roster.registerRequestCallback(acceptFriendRequest);
    _connection.roster.registerCallback(handleContacts);
    _connection.roster.get();
}

function addFriend(friend) {
    if (_connectionStatus === Strophe.Status.CONNECTED) {
        _connection.roster.subscribe(getBareJIDForNode(friend));
    } else {
        _pendingFriends.push(friend);
    }
}

function acceptFriendRequest (from) {
    _connection.roster.authorize(from);
    return true;
}

function handleContacts (roster, item) {
  console.log('roster', roster, item);
    // var friends = [];
    roster.forEach((friend, i) => {
	var username = Strophe.getNodeFromJid(friend.jid);
      loadPrivateChatHistory(friend.jid, "");
	    //     friends.push(username);
      loadUserProfile(username);
    });
    return true;
}

function loadPrivateChatHistory (contact, before) {
  console.log('loading history between', contact);
    if (historyLoadedFor.indexOf(contact) === -1 || before) {
        historyLoadedFor.push(contact);
      _connection.mam.query(
            Strophe.getBareJidFromJid(_myJID),
            {
                'with': contact,
              'before': before,
                'max': 20,
                // TODO strophe.mam is a bit broken.
                // It adds onMessage as handler for all received messages so
                // if you send off multiple queries in parallel the handler is
                // called several times. To workaround we add receiveArchivedPrivateMessage
                // once above and pass a noop here.
                // TODO remove the noop otherwise we're adding one each time we do a query
              onMessage: function () { },
              onComplete: msg => {
                let first = XMPP.parse.RSM(msg);
                if (first) {
                  loadPrivateChatHistory(contact, first);
                }
              }
            }
      );
    }
}

function loadUserProfile (user) {
//  console.log('loading profile', user);
  var jid = getBareJIDForNode(user);
  if (userProfileLoadedFor.indexOf(user) === -1) {
    userProfileLoadedFor.push(user);
    get(
      // TODO fix hardcoded url
      `/di/api/users/${user}/`)
      .done(res => {
        ChatServerActionCreators.receiveUserProfile(res);
      });
  }
}

function receivePrivateMessage (msg) {
    var message = XMPP.parse.privateMessage(msg);
    if (message.composing.length) {
	ChatServerActionCreators.receiveStartTyping(message.from, message.threadID);
    } else {
	if (message.active.length) {
	    ChatServerActionCreators.receiveStopTyping(message.from, message.threadID);
	}
	if (message.ended.length) {
	    ChatServerActionCreators.receiveEndThread(message.threadID, null);
	}
	if (message.text) {
            ChatServerActionCreators.receivePrivateMessage(message);
	}
    }
    return true;
}

var receiveArchivedPrivateMessage = function (msg) {
    var message = XMPP.parse.archivedPrivateMessage(msg);
    if (message) { // TODO don't need if when not querying group messages
	message.isRead = true;
      ChatServerActionCreators.receivePrivateMessage(message, true);
	if (message.ended.length) {
	    ChatServerActionCreators.receiveEndThread(message.threadID);
            // TODO not sure where this call belongs
            getSessionRating(
                message.threadID,
                // TODO use Promise here?
                rating => ChatServerActionCreators.receiveSessionRating(
                    message.threadID,
                    // TODO prob getSession should do this unpacking?
                    rating.rating
                )
            )
	}
    }
    return true;
};

function receivePresence (pres) {
    var status = XMPP.parse.presence(pres);
    ChatServerActionCreators.receiveChatStatus(status);
    return true;
};

function getSessionRating (threadID, callback) {
    $.get(urlUtils.getSessionRating(threadID)).done(callback);
}

function setupLogging () {
    _connection.rawInput = function (data) { console.log('RECV: ', data); };
    _connection.rawOutput = function (data) { console.log('SENT: ', data); };
}

function getBareJIDForNode (node) {
    return node + '@' + _domain;
};

module.exports = {

    connect: function (server, jid, password, nick, log=false) {
	_myJID = jid;
        _nick = nick;
	_domain = Strophe.getDomainFromJid(jid);
	_me = Strophe.getNodeFromJid(jid);

        _connection = new Strophe.Connection('ws://' + server + ':5280/ws-xmpp');
        if (log) {
            setupLogging();
        }
        _connection.connect(
            jid,
	    password,
            onConnectFactory(_connectResolve)
        );
    },

    getAllMessages: function() {
        // simulate retrieving data from a database
        var rawMessages = JSON.parse(localStorage.getItem('messages'));

        // simulate success callback
        ChatServerActionCreators.receiveAll(rawMessages);
    },

    createMessage: function(message, threadID) {
        var roomJID;
        if (message.threadID.indexOf(':') === -1) {
            roomJID = message.threadID + '@muc.' + _domain; // TODO fix hardcoded chat domain
            _connection.muc.groupchat(
                roomJID,
                message.text
            )
        } else {
	    var to = ChatMessageUtils.getMessageOther(message.threadID);
	    var payload = XMPP.create.privateMessage(
	        message.text,
	        _myJID,
	        getBareJIDForNode(to)
	    );
	    _connection.chatstates.addActive(payload);

            payload.c('thread').t(message.threadID);

	    delete sentIsTyping[threadID];
	    _connection.send(payload.tree()); // TODO handle error on message submit
        }
    },

    setStatus: function (code, message) {
	var pres = $pres();
	if (code) {
	    pres.c('show').t(code).up();
	}
	if (message) {
	    pres.c('status').t(message);
	}
	_connection.send(pres.tree());
    },

    // TODO only send this if other person is online? what's spec say?
    startTyping: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	if (!sentIsTyping[threadID]) {
	    sentIsTyping[threadID] = true;
	    _connection.chatstates.sendComposing(
	        getBareJIDForNode(to)
	    );
	}
    },

    stopTyping: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	delete sentIsTyping[threadID];
	_connection.chatstates.sendActive(
	    getBareJIDForNode(to)
	);
    },

    joinChatroom: joinChatroom,

    addFriend: addFriend,

    startSession: function (threadID, participants) {
	var url = urlUtils.startSession();
        $.ajax({
            url: url,
            type: "POST",
            data: JSON.stringify({
		session_id: threadID,
		ratings: [for (p of participants) {user: p}]
	    }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            error: () => console.log('startsession failed')
        })
    },

    rateThread (threadID, rating) {
	var url = urlUtils.rateSession(threadID);
        $.ajax({
            url: url,
            type: "PUT",
            data: JSON.stringify({
		rating: rating
	    }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            error: () => console.log('rate session failed')
        })
    },

    endThread: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	var payload = $msg({
	    from: _myJID,
	    to: getBareJIDForNode(to),
	    type: 'chat'
	});
        payload.c('ended').up();
        payload.c('thread').t(threadID).up();
	// Add empty body so message gets archived
        payload.c('body').up();
	_connection.send(payload.tree()); // TODO handle error on message submit
    },

};
<commit_msg>Another 'X is typing' fix<commit_after>var ChatServerActionCreators = require('../actions/ChatServerActionCreators');
var XMPP = require('./xmpp.js');
var ChatMessageUtils = require('./ChatMessageUtils');
var urlUtils = require('./urlUtils');
import UserProfileStore from '../stores/UserProfileStore';
import { get } from '../../../js/request';

var _connection, // raw connection
    _connectResolve,
    _connectionStatus, _domain, _me, _myJID, _nick;
var _pendingFriends = [];

// TODO I think this state is maybe in the wrong place
// E.g. if we have a ContactStore, it would request history and profile
// to be fetched when a contact is first added?
var historyLoadedFor = [];
var userProfileLoadedFor = [];
//

var sentIsTyping = {};

// Strophe.log = function (level, msg) {
//     console.log(msg);
// };

var connect = new Promise((resolve, reject) => {
    _connectResolve = resolve;
});

function onConnectFactory (resolve) {
    return function (status_code) {
        _connectionStatus = status_code;
        if (status_code == Strophe.Status.CONNECTED) {
            sendInitialPresence();
	    addPrivateChatHandlers();
            _connection.mam.init(_connection);
            _connection.addHandler(
                receiveArchivedPrivateMessage, Strophe.NS.MAM, "message", null);
            getContacts();
            loadUserProfile(Strophe.getNodeFromJid(_myJID));
            _connection.chatstates.init(_connection);
            if (chatConf.hasChatroom) {
                _connection.muc.init(_connection);
	      addGroupChatHandlers();
            }
            if (_pendingFriends.length) {
                _pendingFriends.forEach(f => addFriend(f));
            }
            resolve(_connection);
            ChatServerActionCreators.connect(_connection);
        } else if (status_code == Strophe.Status.DISCONNECTED) {
            ChatServerActionCreators.disconnect();
        }
    }
};

function sendInitialPresence () {
    _connection.send($pres().tree());
}

var getChatrooms = new Promise((resolve, reject) => {
    // TODO not sure here about using a promise inside a promise
    // TODO fix this hack to workaround problems joining the main chatroom
    // when viewing private messages. For now we don't join the chatroom
    // as private and group threads are intermingled in the thread store
    // and that breaks thinsgs.
    if (window.location.href.indexOf('messages') === -1 &&
        window.location.href.indexOf('sessions') === -1) {
        connect.then(connection => {
            var chatDomain = 'muc.' + _domain; // TODO pass in from config
            connection.muc.listRooms(
                chatDomain,
                receiveChatrooms(resolve),
                reject
            )
        });
    }
});

// TODO is there a better pattern to use here?
// Want getChatrooms to be a promise but want .then funcs to receive the parsed roomList
// not the raw XMPP result. Seems I'm going to be writing a lot of factory functions to
// return functions that call `resolve`...
function receiveChatrooms (resolve) {
    return function (result) {
//        console.log('got chatrooms');
        var roomList = XMPP.parse.roomList(result);
        resolve(roomList);
	ChatServerActionCreators.receiveChatrooms(roomList);
    }
};

getChatrooms.then(roomList => {
    if (roomList.length) {
	// TODO something better than these path inspection hacks, pass some explicit option?
	if (window.location.href.indexOf('chatroom') === -1) {
            // Anywhere outside of /chatrooms/ we just want to join the 'main' site chatroom
          let mainRoom = roomList.find(r => r.startsWith('main'));
//          console.log('joining', mainRoom);
          joinChatroom(mainRoom);
	}
    }
});

function joinChatroom (roomJID) {
    if (!chatConf.hasChatroom) {
        return;
    }
    Promise.all([
        connect,  // TODO not sure this is need as getChatrooms already depends on it
        getChatrooms
    ]).then(result => {
        var [connection, roomList] = result;
        if (roomList.indexOf(roomJID) === -1) {
//            console.log('No such room', roomList);
            return;
        }
        // TODO this isn't quite the right place, should probably do
        // when get presence back confirming room join
        ChatServerActionCreators.joinChatroom(roomJID);
        connection.muc.join(
            roomJID,
            _nick
        );
    });
}

function receiveGroupMessage (msg) {
    var message = XMPP.parse.groupMessage(msg);
    // TODO not sure about treating a group message as just another message. Makes some sense, as it's just another thread
    message.threadID = message.to;
    message.authorName = message.from;
    if (message.from) {
	// TODO always get an 'empty' message from the room
	// itself, not sure why
      ChatServerActionCreators.receivePrivateMessage(message, true);
    }
    return true;
};

function receiveGroupPresence (pres) {
    var presence = XMPP.parse.groupPresence(pres);
    if (presence.added) {
      ChatServerActionCreators.receiveOnline(presence.user, presence.room);
      loadUserProfile(presence.user);
    } else if (presence.removed) {
        ChatServerActionCreators.receiveOffline(presence.user, presence.room);
        if (presence.destroyed) {
            ChatServerActionCreators.leaveChatroom(presence.room);
        }
    }
    // TODO ChatServerActionCreators.joinChatroom
    return true;
}

function addPrivateChatHandlers () {
    _connection.addHandler(receivePrivateMessage, null, 'message', 'chat',  null);
    _connection.addHandler(receivePresence, null, 'presence', null,  null);
}

function addGroupChatHandlers() {
  _connection.addHandler(receiveGroupMessage, null, 'message', 'groupchat', null);
  _connection.addHandler(receiveGroupPresence, null, 'presence', null, null);
}

function getContacts () {
    _connection.roster.init(_connection);
    _connection.roster.registerRequestCallback(acceptFriendRequest);
    _connection.roster.registerCallback(handleContacts);
    _connection.roster.get();
}

function addFriend(friend) {
    if (_connectionStatus === Strophe.Status.CONNECTED) {
        _connection.roster.subscribe(getBareJIDForNode(friend));
    } else {
        _pendingFriends.push(friend);
    }
}

function acceptFriendRequest (from) {
    _connection.roster.authorize(from);
    return true;
}

function handleContacts (roster, item) {
  console.log('roster', roster, item);
    // var friends = [];
    roster.forEach((friend, i) => {
	var username = Strophe.getNodeFromJid(friend.jid);
      loadPrivateChatHistory(friend.jid, "");
	    //     friends.push(username);
      loadUserProfile(username);
    });
    return true;
}

function loadPrivateChatHistory (contact, before) {
  console.log('loading history between', contact);
    if (historyLoadedFor.indexOf(contact) === -1 || before) {
        historyLoadedFor.push(contact);
      _connection.mam.query(
            Strophe.getBareJidFromJid(_myJID),
            {
                'with': contact,
              'before': before,
                'max': 20,
                // TODO strophe.mam is a bit broken.
                // It adds onMessage as handler for all received messages so
                // if you send off multiple queries in parallel the handler is
                // called several times. To workaround we add receiveArchivedPrivateMessage
                // once above and pass a noop here.
                // TODO remove the noop otherwise we're adding one each time we do a query
              onMessage: function () { },
              onComplete: msg => {
                let first = XMPP.parse.RSM(msg);
                if (first) {
                  loadPrivateChatHistory(contact, first);
                }
              }
            }
      );
    }
}

function loadUserProfile (user) {
//  console.log('loading profile', user);
  var jid = getBareJIDForNode(user);
  if (userProfileLoadedFor.indexOf(user) === -1) {
    userProfileLoadedFor.push(user);
    get(
      // TODO fix hardcoded url
      `/di/api/users/${user}/`)
      .done(res => {
        ChatServerActionCreators.receiveUserProfile(res);
      });
  }
}

function receivePrivateMessage (msg) {
    var message = XMPP.parse.privateMessage(msg);
    if (message.composing.length) {
	ChatServerActionCreators.receiveStartTyping(message.from, message.threadID);
    } else {
	if (message.active.length) {
	    ChatServerActionCreators.receiveStopTyping(message.from, message.threadID);
	}
	if (message.ended.length) {
	    ChatServerActionCreators.receiveEndThread(message.threadID, null);
	}
	if (message.text) {
            ChatServerActionCreators.receivePrivateMessage(message);
	}
    }
    return true;
}

var receiveArchivedPrivateMessage = function (msg) {
    var message = XMPP.parse.archivedPrivateMessage(msg);
    if (message) { // TODO don't need if when not querying group messages
	message.isRead = true;
      ChatServerActionCreators.receivePrivateMessage(message, true);
	if (message.ended.length) {
	    ChatServerActionCreators.receiveEndThread(message.threadID);
            // TODO not sure where this call belongs
            getSessionRating(
                message.threadID,
                // TODO use Promise here?
                rating => ChatServerActionCreators.receiveSessionRating(
                    message.threadID,
                    // TODO prob getSession should do this unpacking?
                    rating.rating
                )
            )
	}
    }
    return true;
};

function receivePresence (pres) {
    var status = XMPP.parse.presence(pres);
    ChatServerActionCreators.receiveChatStatus(status);
    return true;
};

function getSessionRating (threadID, callback) {
    $.get(urlUtils.getSessionRating(threadID)).done(callback);
}

function setupLogging () {
    _connection.rawInput = function (data) { console.log('RECV: ', data); };
    _connection.rawOutput = function (data) { console.log('SENT: ', data); };
}

function getBareJIDForNode (node) {
    return node + '@' + _domain;
};

module.exports = {

    connect: function (server, jid, password, nick, log=false) {
	_myJID = jid;
        _nick = nick;
	_domain = Strophe.getDomainFromJid(jid);
	_me = Strophe.getNodeFromJid(jid);

        _connection = new Strophe.Connection('ws://' + server + ':5280/ws-xmpp');
        if (log) {
            setupLogging();
        }
        _connection.connect(
            jid,
	    password,
            onConnectFactory(_connectResolve)
        );
    },

    getAllMessages: function() {
        // simulate retrieving data from a database
        var rawMessages = JSON.parse(localStorage.getItem('messages'));

        // simulate success callback
        ChatServerActionCreators.receiveAll(rawMessages);
    },

    createMessage: function(message, threadID) {
        var roomJID;
        if (message.threadID.indexOf(':') === -1) {
            roomJID = message.threadID + '@muc.' + _domain; // TODO fix hardcoded chat domain
            _connection.muc.groupchat(
                roomJID,
                message.text
            )
        } else {
	    var to = ChatMessageUtils.getMessageOther(message.threadID);
	    var payload = XMPP.create.privateMessage(
	        message.text,
	        _myJID,
	        getBareJIDForNode(to)
	    );
	    _connection.chatstates.addActive(payload);

            payload.c('thread').t(message.threadID);

	    delete sentIsTyping[message.threadID];
	    _connection.send(payload.tree()); // TODO handle error on message submit
        }
    },

    setStatus: function (code, message) {
	var pres = $pres();
	if (code) {
	    pres.c('show').t(code).up();
	}
	if (message) {
	    pres.c('status').t(message);
	}
	_connection.send(pres.tree());
    },

    // TODO only send this if other person is online? what's spec say?
    startTyping: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	if (!sentIsTyping[threadID]) {
	    sentIsTyping[threadID] = true;
	    _connection.chatstates.sendComposing(
	        getBareJIDForNode(to)
	    );
	}
    },

    stopTyping: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	delete sentIsTyping[threadID];
	_connection.chatstates.sendActive(
	    getBareJIDForNode(to)
	);
    },

    joinChatroom: joinChatroom,

    addFriend: addFriend,

    startSession: function (threadID, participants) {
	var url = urlUtils.startSession();
        $.ajax({
            url: url,
            type: "POST",
            data: JSON.stringify({
		session_id: threadID,
		ratings: [for (p of participants) {user: p}]
	    }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            error: () => console.log('startsession failed')
        })
    },

    rateThread (threadID, rating) {
	var url = urlUtils.rateSession(threadID);
        $.ajax({
            url: url,
            type: "PUT",
            data: JSON.stringify({
		rating: rating
	    }),
            contentType: "application/json; charset=utf-8",
            dataType: "json",
            error: () => console.log('rate session failed')
        })
    },

    endThread: function (threadID) {
	var to = ChatMessageUtils.getMessageOther(threadID);
	var payload = $msg({
	    from: _myJID,
	    to: getBareJIDForNode(to),
	    type: 'chat'
	});
        payload.c('ended').up();
        payload.c('thread').t(threadID).up();
	// Add empty body so message gets archived
        payload.c('body').up();
	_connection.send(payload.tree()); // TODO handle error on message submit
    },

};
<|endoftext|>


<commit_before>/**
 * I18n.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*jshint smarttabs:true, undef:true, unused:true, latedef:true, curly:true, bitwise:true, scripturl:true, browser:true */
/*global define:true */

define("moxie/core/I18n", [
	"moxie/core/utils/Basic"
], function(Basic) {
	var i18n = {};

	return {
		/**
		 * Extends the language pack object with new items.
		 *
		 * @param {Object} pack Language pack items to add.
		 * @return {Object} Extended language pack object.
		 */
		addI18n: function(pack) {
			return Basic.extend(i18n, pack);
		},

		/**
		 * Translates the specified string by checking for the english string in the language pack lookup.
		 *
		 * @param {String} str String to look for.
		 * @return {String} Translated string or the input string if it wasn't found.
		 */
		translate: function(str) {
			return i18n[str] || str;
		},

		/**
		 * Shortcut for translate function
		 *
		 * @param {String} str String to look for.
		 * @return {String} Translated string or the input string if it wasn't found.
		 */
		_: function(str) {
			return this.translate(str);
		}
	};
});<commit_msg>I18n: Add simplified sprintf implementation.<commit_after>/**
 * I18n.js
 *
 * Copyright 2013, Moxiecode Systems AB
 * Released under GPL License.
 *
 * License: http://www.plupload.com/license
 * Contributing: http://www.plupload.com/contributing
 */

/*jshint smarttabs:true, undef:true, unused:true, latedef:true, curly:true, bitwise:true, scripturl:true, browser:true */
/*global define:true */

define("moxie/core/I18n", [
	"moxie/core/utils/Basic"
], function(Basic) {
	var i18n = {};

	return {
		/**
		 * Extends the language pack object with new items.
		 *
		 * @param {Object} pack Language pack items to add.
		 * @return {Object} Extended language pack object.
		 */
		addI18n: function(pack) {
			return Basic.extend(i18n, pack);
		},

		/**
		 * Translates the specified string by checking for the english string in the language pack lookup.
		 *
		 * @param {String} str String to look for.
		 * @return {String} Translated string or the input string if it wasn't found.
		 */
		translate: function(str) {
			return i18n[str] || str;
		},

		/**
		 * Shortcut for translate function
		 *
		 * @param {String} str String to look for.
		 * @return {String} Translated string or the input string if it wasn't found.
		 */
		_: function(str) {
			return this.translate(str);
		},

		/**
		 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
		 *
		 * @param {String} str String with tokens
		 * @return {String} String with replaced tokens
		 */
		sprintf: function(str) {
			var args = [].slice.call(arguments, 1), reStr = '';

			str.split(/%[sdf]/).forEach(function(part) {
				reStr += part;
				if (args.length) {
					 reStr += args.shift();
				}
			});
			return reStr;
		}
	};
});<|endoftext|>


<commit_before>define([], function () {

	var _makeScope = function (props) {
		var scopeValue = {};
		props.forEach(function (name) {
			scopeValue[name] = "=";
		});
		return scopeValue; // {p: '=', ... }
	};

	var _makeArgs = function (props, scope) {
		var args = {};
		props.forEach(function(p){
			args[p] = scope[p];
		});
		return args; // {p: $scope.p, ... }
	};

	var _setWatchers = function (scope, props) {
		props.forEach(function(p){
			// if scope property changes, update widget property
			scope.$watch(p, function (newValue) {
				if (newValue){
					scope.widget[p] = newValue;
				}
			});

			// if widget property changes, update scope property
			scope.widget.watch(p, function(){
				scope[p] = scope.widget[p];
				setTimeout(function () { scope.$apply(); }, 1);
			});
		});
	};

	var _nameWidget = function (name) {
		return "ng" + name;
	};

	return function (name, widget, props) {
		angular.module(name, [])
			.directive(_nameWidget(name), function () {
				return {
					restrict: 'E',
					scope: _makeScope(props),
					controller: function ($scope) {
						// init
						$scope.widget = new widget(_makeArgs(props, $scope));
					},
					link: function (scope, elem, attrs) {
						// insert widget in angular directive
						elem.append(scope.widget);

						// update widget.value when ngModel is changed
						_setWatchers(scope, props);
					}
				};
			});
	};
});
<commit_msg>changed ngWidget implementation to be more flexible with scope isolation<commit_after>define([], function () {

	// helpers
	var isUndefined = function (value) {
		return typeof value === "undefined";
	};

	var intersectArrays = function (arr1, arr2) {
		var res = [];
		arr1.forEach(function(p){
			if (arr2.indexOf(p) !== -1) {
				res.push(p);
			}
		});
		return res;
	};

	var overwriteObject = function (obj1, obj2) {
		Object.keys(obj2).forEach(function(p){
			obj1[p] = obj2[p];
		});
		return obj1;
	};

	// properties of a widget
	var getDefaultProps = function (constructor) {
		// getting all the props
		var instance = new constructor();
		var allprops = Object.getPrototypeOf(instance)._getProps();
		instance.destroy();

		// filtring relevant props
		var excluded = ["baseClass", "focused", "widgetId", "invalidProperties", "invalidRendering"];
		var isExcluded = function (property) {
			return (excluded.indexOf(property) === -1);
		}
		var props = allprops.filter(isExcluded);
		return props;
	};

	var defaultScope = function (props) {
		var s = {};
		props.forEach(function(p){
			s[p] = '@';
		});
		return s;
	};

	var makeIsolatedScope = function (constructor, overwrite) {
		var myprops = getDefaultProps(constructor)
		var s = defaultScope(myprops)
		if (typeof overwrite === "object"){ // if overwrite defined, overwrite the scope
			overwriteObject(s, overwrite);
		}
		return s;
	};

	var setWatchers = function (scope, props) {
		Object.keys(props).forEach(function(p){
			// if scope property changes, update widget property
			scope.$watch(p, function (newValue) {
				if (! isUndefined(newValue)){
					scope.widget[p] = newValue;
				}
			});

			// if widget property changes, update scope property
			scope.widget.watch(p, function(){
				scope[p] = scope.widget[p];
				setTimeout(function () { scope.$apply(); }, 1);
			});
		});
	};

	var _nameWidget = function (name) {
		return "ng" + name;
	};

	return function (name, widget, overwrite) {
		angular.module(name, [])
			.directive(_nameWidget(name), function () {
				var isolatedScope = makeIsolatedScope(widget, overwrite);
				var directive = {
					restrict: 'E',
					controller: function ($scope) { },
					scope: isolatedScope,
					link: function (scope, elem, attrs) {
						// insert widget in angular directive
						var mywidget = new widget();
						scope.widget = mywidget;
						elem.append(scope.widget);

						// bind widget propreties with directive scope
						setWatchers(scope, isolatedScope);
					}
				}
				return directive;
			});
	};
});
<|endoftext|>


<commit_before>/*---------------------------------------------------------
 * OpenERP base_calendar
 *---------------------------------------------------------*/

openerp.base_calendar = function(openerp) {
QWeb.add_template('/base_calendar/static/src/xml/base_calendar.xml');
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
// Dhtmlx scheduler ?
	init: function(view_manager, session, element_id, dataset, view_id){
		this._super(session, element_id);
		this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
		this.context = this.dataset.context || {};
	},
	start: function() {
		this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
	},
    on_loaded: function(data) {
		this.calendar_fields = {};
		this.ids = this.dataset.ids;
		this.day_lenth = 8;
		this.color_values = [];
		this.info_fields = [];

        this.fields_view = data.fields_view;
        this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
		this.view_id = this.fields_view.view_id;

        this.date_start = this.fields_view.arch.attrs.date_start;
		this.date_delay = this.fields_view.arch.attrs.date_delay;
		this.date_stop = this.fields_view.arch.attrs.date_stop;

        this.colors = this.fields_view.arch.attrs.colors;
		this.day_length = this.fields_view.arch.attrs.day_length || 8;
		this.color_field = this.fields_view.arch.attrs.color;
		this.fields =  this.fields_view.fields;

        //* Calendar Fields *
		this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};

		if(this.date_delay)
			this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};

		if(this.date_stop)
			this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};

		//* ------- *

        for(var fld=0;fld<this.fields_view.arch.children.length;fld++) {
			this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
		}

        this.load_scheduler();
    },

    load_scheduler: function() {
        var self = this;
        this.dataset.read_slice([], 0, false, function(events) {
            if (self.session.locale_code) {
                $LAB.setOptions({AlwaysPreserveOrder: true})
                .script([
                    '/base_calendar/static/lib/dhtmlxScheduler/sources/locale_'+self.session.locale_code+'.js',
                    '/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_'+self.session.locale_code+'.js'
                ])
                .wait(function() {
                    self.schedule_events(events);
                });

            } else {
                self.schedule_events(events);
            }
        });
    },

    schedule_events: function(events) {
        this.$element.html(QWeb.render("CalendarView", {"fields_view": this.fields_view}));
        /*
		 * Initialize dhtmlx Schedular
		 */

        scheduler.clearAll();
        scheduler.config.api_date="%Y-%m-%d %H:%M:%S";
        scheduler.config.details_on_dblclick=true;
        scheduler.config.details_on_create = true;

        if(this.fields[this.date_start]['type'] == 'time') {
            scheduler.config.xml_date="%H:%M:%S";
        } else {
            scheduler.config.xml_date="%Y-%m-%d %H:%M:%S";

        }

        scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views

        // Initialize Sceduler
		scheduler.init('openerp_scheduler',null,"month");

        //To parse Events we have to convert date Format
        var res_events = [];
        for(var e=0;e<events.length;e++) {
            var evt = events[e];
            if(!evt[this.date_start]) {
                this.notification.warn("Start date is not defined for event :", evt['id']);
                break;
            }

            if (this.fields[this.date_start]['type'] == 'date') {
                evt[this.date_start] = openerp.base.parse_date(evt[this.date_start]).set({hour: 9}).toString('yyyy-MM-dd HH:mm:ss')
            }
            if(this.date_stop && evt[this.date_stop] && this.fields[this.date_stop]['type'] == 'date') {
                evt[this.date_stop] = openerp.base.parse_date(evt[this.date_stop]).set({hour: 17}).toString('yyyy-MM-dd HH:mm:ss')
            }
            res_events.push(this.convert_event(evt))
        }
        scheduler.parse(res_events,"json");
        jQuery('#dhx_minical_icon').bind('click', this.mini_calendar);

        // Event Options Click,edit
        var self = this;
        scheduler.attachEvent(
            "onDblClick",
            function(event_id, e) {
                self.popup_event(event_id);
                e.stopPropagation();
                e.preventDefault();
            }
        );

        scheduler.attachEvent(
            "onEventCreated",
            function(event_id, e) {
                //Replace default Lightbox with Popup Form of new Event

                scheduler.showLightbox = function(){
                    //Delete Newly created Event,Later we reload Scheduler
                    scheduler.deleteEvent(event_id)
                    self.popup_event();
                    e.stopPropagation();
                    e.preventDefault();
                }
            }
        );
    },

    convert_event: function(event) {
        var res_text = '';
        var res_description = [];
        var start = event[this.date_start];
        var end = event[this.date_delay] || 1;
        var span = 0;
        if(this.info_fields) {
            var fld = event[this.info_fields[0]];
            if(typeof fld == 'object') {

                res_text = fld[fld.length -1];
            } else {
                res_text = fld
            }
            var sliced_info_fields = this.info_fields.slice(1);
            for(sl_fld in sliced_info_fields) {
                var slc_fld = event[sliced_info_fields[sl_fld]];
                if(typeof slc_fld == 'object') {
                  res_description.push(slc_fld[slc_fld.length - 1])
                } else {
                    if(slc_fld) {
                        res_description.push(slc_fld);
                    }
                }
            }
        }
        if(start && end){
            var n = 0;
            var h = end;
            if (end == this.day_length) {
                span = 1
            } else if(end > this.day_length) {
                n = end / this.day_length;
                h = end % this.day_length;
                n = parseInt(Math.floor(n));

                if(h > 0)
                    span = n + 1
                else
                    span = n
            }
            var end_date = openerp.base.parse_datetime(start);
            end = end_date.add({hours: h, minutes: n})
        }
        if(start && this.date_stop) {
            var tds = start = openerp.base.parse_datetime(start);
            var tde = ends = openerp.base.parse_datetime(event[this.date_stop]);
            if(event[this.date_stop] == undefined) {
                if(tds) {
                    end = (tds.getOrdinalNumber() + 60 * 60)
                }
            }

            if(tds && tde) {
                //time.mktime equivalent
                tds = (tds.getOrdinalNumber() / 1e3 >> 0) - (tds.getOrdinalNumber() < 0);
                tde = (tde.getOrdinalNumber() / 1e3 >> 0) - (tde.getOrdinalNumber() < 0);

            }
            if(tds >= tde) {
                 tde = tds + 60 * 60;
            }

            n = (tde - tds) / (60 * 60);
            if (n >= this.day_length) {
                span = Math.ceil(n / 24);
            }
        }

        return {
            'start_date': start.toString('yyyy-MM-dd HH:mm:ss'),
            'end_date': end.toString('yyyy-MM-dd HH:mm:ss'),
            'text': res_text,
            'id': event['id'],
            'title': res_description.join()
            }
    },

    mini_calendar: function() {

		if(scheduler.isCalendarVisible()) {
			scheduler.destroyCalendar();
		} else {
			scheduler.renderCalendar({
				position:"dhx_minical_icon",
            	date:scheduler._date,
            	navigation:true,
				handler:function(date,calendar){
	               scheduler.setCurrentView(date);
	               scheduler.destroyCalendar()
	            }
			});
		}
	},

    do_search: function(domains, contexts, groupbys) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            // TODO: handle non-empty results.group_by with read_group
            self.dataset.context = self.context = results.context;
            self.dataset.domain = self.domain = results.domain;
            self.dataset.read_slice(self.fields, 0, self.limit,function(events){
                self.schedule_events(events)
            });
        });
    },

	do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    popup_event: function(event_id) {

    	var self = this;
    	if(event_id) event_id = parseInt(event_id, 10);

        var action = {
    		"res_model": this.dataset.model,
    		"res_id": event_id,
            "views":[[false,"form"]],
            "type":"ir.actions.act_window",
            "view_type":"form",
            "view_mode":"form"
        }

        action.flags = {
    		search_view: false,
            sidebar : false,
            views_switcher : false,
            action_buttons : false,
            pager: false
            }
        var element_id = _.uniqueId("act_window_dialog");

        var dialog = jQuery('<div>', {
            'id': element_id
            }).dialog({
                modal: true,
                width: 'auto',
                height: 'auto',
                buttons: {
            		Cancel: function() {
            			$(this).dialog("destroy");
            		},
            		Save: function() {
            			var view_manager = action_manager.viewmanager;
            			var _dialog = this;
            			view_manager.views[view_manager.active_view].controller.do_save(function(r) {
            				$(_dialog).dialog("destroy");
            				self.start();
            			})
            		}
            	}
        });
        var action_manager = new openerp.base.ActionManager(this.session, element_id);
        action_manager.start();
        action_manager.do_action(action);

        //Default_get
        if(!event_id) action_manager.viewmanager.dataset.index = null;
    }
});

};

// DEBUG_RPC:rpc.request:('execute', 'addons-dsh-l10n_us', 1, '*', ('ir.filters', 'get_filters', u'res.partner'))
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[FIX] On Resize event try to save event else create new.<commit_after>/*---------------------------------------------------------
 * OpenERP base_calendar
 *---------------------------------------------------------*/

openerp.base_calendar = function(openerp) {
QWeb.add_template('/base_calendar/static/src/xml/base_calendar.xml');
openerp.base.views.add('calendar', 'openerp.base_calendar.CalendarView');
openerp.base_calendar.CalendarView = openerp.base.Controller.extend({
// Dhtmlx scheduler ?
	init: function(view_manager, session, element_id, dataset, view_id){
		this._super(session, element_id);
		this.view_manager = view_manager;
        this.dataset = dataset;
        this.model = dataset.model;
        this.view_id = view_id;
        this.domain = this.dataset.domain || [];
		this.context = this.dataset.context || {};
	},
	start: function() {
		this.rpc("/base_calendar/calendarview/load", {"model": this.model, "view_id": this.view_id}, this.on_loaded);
	},
    on_loaded: function(data) {
		this.calendar_fields = {};
		this.ids = this.dataset.ids;
		this.day_lenth = 8;
		this.color_values = [];
		this.info_fields = [];

        this.fields_view = data.fields_view;
        this.name = this.fields_view.name || this.fields_view.arch.attrs.string;
		this.view_id = this.fields_view.view_id;

        this.date_start = this.fields_view.arch.attrs.date_start;
		this.date_delay = this.fields_view.arch.attrs.date_delay;
		this.date_stop = this.fields_view.arch.attrs.date_stop;

        this.colors = this.fields_view.arch.attrs.colors;
		this.day_length = this.fields_view.arch.attrs.day_length || 8;
		this.color_field = this.fields_view.arch.attrs.color;
		this.fields =  this.fields_view.fields;

        //* Calendar Fields *
		this.calendar_fields['date_start'] = {'name': this.date_start, 'kind': this.fields[this.date_start]['type']};

		if(this.date_delay)
			this.calendar_fields['date_delay'] = {'name': this.date_delay, 'kind': this.fields[this.date_delay]['type']};

		if(this.date_stop)
			this.calendar_fields['date_stop'] = {'name': this.date_stop, 'kind': this.fields[this.date_stop]['type']};

		//* ------- *

        for(var fld=0;fld<this.fields_view.arch.children.length;fld++) {
			this.info_fields.push(this.fields_view.arch.children[fld].attrs.name);
		}

        this.load_scheduler();
    },

    load_scheduler: function() {
        var self = this;
        this.dataset.read_slice([], 0, false, function(events) {
            if (self.session.locale_code) {
                $LAB.setOptions({AlwaysPreserveOrder: true})
                .script([
                    '/base_calendar/static/lib/dhtmlxScheduler/sources/locale_'+self.session.locale_code+'.js',
                    '/base_calendar/static/lib/dhtmlxScheduler/sources/locale_recurring_'+self.session.locale_code+'.js'
                ])
                .wait(function() {
                    self.schedule_events(events);
                });

            } else {
                self.schedule_events(events);
            }
        });
    },

    schedule_events: function(events) {
        this.$element.html(QWeb.render("CalendarView", {"fields_view": this.fields_view}));
        /*
		 * Initialize dhtmlx Schedular
		 */

        scheduler.clearAll();
        scheduler.config.api_date="%Y-%m-%d %H:%M:%S";
        scheduler.config.details_on_dblclick=true;
        scheduler.config.details_on_create = true;

        if(this.fields[this.date_start]['type'] == 'time') {
            scheduler.config.xml_date="%H:%M:%S";
        } else {
            scheduler.config.xml_date="%Y-%m-%d %H:%M:%S";

        }

        scheduler.config.multi_day = true; //Multi day events are not rendered in daily and weekly views

        // Initialize Sceduler
		scheduler.init('openerp_scheduler',null,"month");

        //To parse Events we have to convert date Format
        var res_events = [];
        for(var e=0;e<events.length;e++) {
            var evt = events[e];
            if(!evt[this.date_start]) {
                this.notification.warn("Start date is not defined for event :", evt['id']);
                break;
            }

            if (this.fields[this.date_start]['type'] == 'date') {
                evt[this.date_start] = openerp.base.parse_date(evt[this.date_start]).set({hour: 9}).toString('yyyy-MM-dd HH:mm:ss')
            }
            if(this.date_stop && evt[this.date_stop] && this.fields[this.date_stop]['type'] == 'date') {
                evt[this.date_stop] = openerp.base.parse_date(evt[this.date_stop]).set({hour: 17}).toString('yyyy-MM-dd HH:mm:ss')
            }
            res_events.push(this.convert_event(evt))
        }
        scheduler.parse(res_events,"json");
        jQuery('#dhx_minical_icon').bind('click', this.mini_calendar);

        // Event Options Click,edit
        var self = this;
        scheduler.attachEvent(
            "onDblClick",
            function(event_id, e) {
                self.popup_event(event_id);
                e.stopPropagation();
                e.preventDefault();
            }
        );

        scheduler.attachEvent(
            "onEventCreated",
            function(event_id, e) {
                //Replace default Lightbox with Popup Form of new Event

                scheduler.showLightbox = function(){
                    //Delete Newly created Event,Later we reload Scheduler
                    scheduler.deleteEvent(event_id)
                    self.popup_event();
                    e.stopPropagation();
                    e.preventDefault();
                }
            }
        );

        scheduler.attachEvent("onBeforeEventChanged", function(event_obj, native_event, is_new) {
        	var is_event_exist = jQuery.inArray(event_obj.id, self.dataset.ids);
        	if(is_event_exist >= 0 && !is_new) {
        		// try to save Event.
        	} else {
        		// new Event.
        		return true;
        	}
        });
    },

    convert_event: function(event) {
        var res_text = '';
        var res_description = [];
        var start = event[this.date_start];
        var end = event[this.date_delay] || 1;
        var span = 0;
        if(this.info_fields) {
            var fld = event[this.info_fields[0]];
            if(typeof fld == 'object') {

                res_text = fld[fld.length -1];
            } else {
                res_text = fld
            }
            var sliced_info_fields = this.info_fields.slice(1);
            for(sl_fld in sliced_info_fields) {
                var slc_fld = event[sliced_info_fields[sl_fld]];
                if(typeof slc_fld == 'object') {
                  res_description.push(slc_fld[slc_fld.length - 1])
                } else {
                    if(slc_fld) {
                        res_description.push(slc_fld);
                    }
                }
            }
        }
        if(start && end){
            var n = 0;
            var h = end;
            if (end == this.day_length) {
                span = 1
            } else if(end > this.day_length) {
                n = end / this.day_length;
                h = end % this.day_length;
                n = parseInt(Math.floor(n));

                if(h > 0)
                    span = n + 1
                else
                    span = n
            }
            var end_date = openerp.base.parse_datetime(start);
            end = end_date.add({hours: h, minutes: n})
        }
        if(start && this.date_stop) {
            var tds = start = openerp.base.parse_datetime(start);
            var tde = ends = openerp.base.parse_datetime(event[this.date_stop]);
            if(event[this.date_stop] == undefined) {
                if(tds) {
                    end = (tds.getOrdinalNumber() + 60 * 60)
                }
            }

            if(tds && tde) {
                //time.mktime equivalent
                tds = (tds.getOrdinalNumber() / 1e3 >> 0) - (tds.getOrdinalNumber() < 0);
                tde = (tde.getOrdinalNumber() / 1e3 >> 0) - (tde.getOrdinalNumber() < 0);

            }
            if(tds >= tde) {
                 tde = tds + 60 * 60;
            }

            n = (tde - tds) / (60 * 60);
            if (n >= this.day_length) {
                span = Math.ceil(n / 24);
            }
        }

        return {
            'start_date': start.toString('yyyy-MM-dd HH:mm:ss'),
            'end_date': end.toString('yyyy-MM-dd HH:mm:ss'),
            'text': res_text,
            'id': event['id'],
            'title': res_description.join()
            }
    },

    mini_calendar: function() {

		if(scheduler.isCalendarVisible()) {
			scheduler.destroyCalendar();
		} else {
			scheduler.renderCalendar({
				position:"dhx_minical_icon",
            	date:scheduler._date,
            	navigation:true,
				handler:function(date,calendar){
	               scheduler.setCurrentView(date);
	               scheduler.destroyCalendar()
	            }
			});
		}
	},

    do_search: function(domains, contexts, groupbys) {
        var self = this;
        this.rpc('/base/session/eval_domain_and_context', {
            domains: domains,
            contexts: contexts,
            group_by_seq: groupbys
        }, function (results) {
            // TODO: handle non-empty results.group_by with read_group
            self.dataset.context = self.context = results.context;
            self.dataset.domain = self.domain = results.domain;
            self.dataset.read_slice(self.fields, 0, self.limit,function(events){
                self.schedule_events(events)
            });
        });
    },

	do_show: function () {
        this.$element.show();
    },

    do_hide: function () {
        this.$element.hide();
    },

    popup_event: function(event_id) {

    	var self = this;
    	if(event_id) event_id = parseInt(event_id, 10);

        var action = {
    		"res_model": this.dataset.model,
    		"res_id": event_id,
            "views":[[false,"form"]],
            "type":"ir.actions.act_window",
            "view_type":"form",
            "view_mode":"form"
        }

        action.flags = {
    		search_view: false,
            sidebar : false,
            views_switcher : false,
            action_buttons : false,
            pager: false
            }
        var element_id = _.uniqueId("act_window_dialog");

        var dialog = jQuery('<div>', {
            'id': element_id
            }).dialog({
                modal: true,
                width: 'auto',
                height: 'auto',
                buttons: {
            		Cancel: function() {
            			$(this).dialog("destroy");
            		},
            		Save: function() {
            			var view_manager = action_manager.viewmanager;
            			var _dialog = this;
            			view_manager.views[view_manager.active_view].controller.do_save(function(r) {
            				$(_dialog).dialog("destroy");
            				self.start();
            			})
            		}
            	}
        });
        var action_manager = new openerp.base.ActionManager(this.session, element_id);
        action_manager.start();
        action_manager.do_action(action);

        //Default_get
        if(!event_id) action_manager.viewmanager.dataset.index = null;
    }
});

};

// DEBUG_RPC:rpc.request:('execute', 'addons-dsh-l10n_us', 1, '*', ('ir.filters', 'get_filters', u'res.partner'))
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>


<commit_before>(function($beerApp, $angular) {

    "use strict";

    /**
     * @controller BeerController
     * @param $scope {Object}
     */
    $beerApp.controller('BeerController', function beerController($scope, $http, PourOver) {

        /**
         * @method request
         * @param path {String}
         * @param params {Object}
         * @return {Object}
         */
        $scope.request = function request(path, params) {

            // Initialise the AJAX request for the data!
            return $http.get(path, params || {});

        };

        var people = [
            { name: 'Adam', age: 12, likes: ['cats', 'hedgehogs'] },
            { name: 'Maria', age: 23, likes: ['cats', 'tortoises'] },
            { name: 'Artem', age: 16, likes: ['dogs'] },
            { name: 'Adam', age: 25, likes: ['cats', 'hedgehogs'] },
            { name: 'Gabriele', age: 33, likes: ['dogs', 'cats'] }
        ];

        $scope.collection = new PourOver(people);

        $scope.collection.addExactFilter('name');
        $scope.collection.addExactFilter('age');
        $scope.collection.addInclusionFilter('likes');
//        $scope.collection.addItem({ name: 'Galina', age: 23 });

        // Fetch the beers, sunshine!
        $scope.request('beers', function success(response) {
            console.log(response);
        });

    });

})(window.beerApp, window.angular);<commit_msg>Controller formatting<commit_after>(function($beerApp, $angular) {

    "use strict";

    /**
     * @controller BeerController
     * @param $scope {Object}
     */
    $beerApp.controller('BeerController', function beerController($scope, $http, PourOver) {

        /**
         * @method request
         * @param path {String}
         * @param params {Object}
         * @return {Object}
         */
        $scope.request = function request(path, params) {

            // Initialise the AJAX request for the data!
            return $http.get(path, params || {});

        };

        var people = [
            { name: 'Adam',         age: 12,    likes: ['cats', 'hedgehogs'] },
            { name: 'Maria',        age: 23,    likes: ['cats', 'tortoises'] },
            { name: 'Artem',        age: 16,    likes: ['dogs'] },
            { name: 'Adam',         age: 25,    likes: ['cats', 'hedgehogs'] },
            { name: 'Gabriele',     age: 33,    likes: ['dogs', 'cats'] }
        ];

        $scope.collection = new PourOver(people);

        $scope.collection.addExactFilter('name');
        $scope.collection.addExactFilter('age');
        $scope.collection.addInclusionFilter('likes');
//        $scope.collection.addItem({ name: 'Galina', age: 23 });

        // Fetch the beers, sunshine!
        $scope.request('beers', function success(response) {
            console.log(response);
        });

    });

})(window.beerApp, window.angular);<|endoftext|>


<commit_before>window.semaUtils = (function () {
    var utils = {};
    var ledCharacteristic = null;
    var remoteUrl = 'http://192.168.1.228:3001';

    /**
     *
     */
    utils.log = (traceMessage, level) => {
        if(window.semaDebugMode) {
            switch(level) {
                case 'error':
                    console.error('[SIP] ' + traceMessage);
                    break;
                case 'info':
                    console.info('[SIP] ' + traceMessage);
                    break;
                case 'warn':
                    console.warn('[SIP] ' + traceMessage);
                    break;
                default:
                    console.log('[SIP] ' + traceMessage);
            }
        }
    };

    /**
     *
     */
    utils.getSettings = (callback) => {
        $.ajax({
            url: '/api/settings',
            success: function(data) {
                callback(data);
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.requestSensorState = (sensor) => {
        var promise = new Promise((resolve, reject) => {
            $.ajax({
                url: '/api/' + sensor,
                success: (data) => {
                    resolve(data);
                },
                error: (err) => {
                    reject(err);
                },
                cache: false
            });
        });
        return promise;
    };

    /**
     *
     */
    utils.requestSensorData = (endpoint, chart, callback) => {
        utils.log('Calling to ' + endpoint);

        // "Sanitize" the input
        if(endpoint.charAt(0) === '/') {
            endpoint = endpoint.slice(1);
        }

        $.ajax({
            url: endpoint,
            success: function(data) {
                var series = chart.series[0],
                    shift = series.data.length > 20;

                // add the points
                for(let i=0; i<data.lastValues.length; i++) {
                    chart.series[0].addPoint(data.lastValues[i], true, shift);
                }

                callback();
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.sendX10Command = (device, action, callback) => {
        $.ajax({
            type: 'post',
            url: remoteUrl + '/x10',
            data: {
                device: device,
                action: action
            },
            success: function() {
                callback();
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.getSongList = (callback) => {
        $.ajax({
            url: remoteUrl + '/library',
            success: function(data) {
                callback(data);
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.playSong = (song) => {
        $.ajax({
            type: 'post',
            data: { song: song },
            url: remoteUrl + '/library/play',
            success: function() { },
            error: function() {
                // Check if there was an error (erro handler)
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.stopPlaying = () => {
        $.ajax({
            url: remoteUrl + '/library/stop',
            success: function(data) {
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.forwardPlaying = () => {
        $.ajax({
            url: remoteUrl + '/library/forward',
            success: function(data) {
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.connectToBulb = () => {
        if(navigator.bluetooth) {
            navigator.bluetooth.requestDevice({
                filters: [{ services: [0xffe5] }]
            })
            .then(function(device) {
                // Step 2: Connect to it
                console.log('setp2: ', device);
                return device.gatt.connect();
            })
            .then(function(server) {
                // Step 3: Get the Service
                console.log('setp3: ', server);
                return server.getPrimaryService(0xffe5);
            })
            .then(function(service) {
                // Step 4: get the Characteristic
                console.log('setp4: ', service);
                return service.getCharacteristic(0xffe9);
            })
            .then(function(characteristic) {
                // Step 5: Write to the characteristic
                console.log('setp5: ', characteristic);
                ledCharacteristic = characteristic;
                var data = new Uint8Array([0xbb, 0x25, 0x05, 0x44]);
                return characteristic.writeValue(data);
            })
            .catch(function(error) {
                // And of course: error handling!
                console.error('Connection failed! ', error);
            });
        } else {
            alert('Error, bluetooth not supported or disconnected');
        }
    };

    /**
     *
     */
    utils.setBulbColor = (r, g, b) => {
        let data = new Uint8Array([0x56, r, g, b, 0x00, 0xf0, 0xaa]);
        return ledCharacteristic.writeValue(data)
            .catch(err => console.log('Error when writing value! ', err));
    };

    /**
     *
     */
    utils.turnOn = () => {
        let data = new Uint8Array([0xcc, 0x23, 0x33]);
        return ledCharacteristic.writeValue(data)
            .then(() => {})
            .catch(err => console.log('Error when turning on! ', err));
    }

    /**
     *
     */
    utils.turnOff = () => {
        let data = new Uint8Array([0xcc, 0x24, 0x33]);
        return ledCharacteristic.writeValue(data)
            .then(() => {})
            .catch(err => console.log('Error when turning off! ', err));
    }

    return utils;
}($));
<commit_msg>Fixed utils method<commit_after>window.semaUtils = (function () {
    var utils = {};
    var ledCharacteristic = null;
    var remoteUrl = 'http://192.168.1.228:3001';

    /**
     *
     */
    utils.log = (traceMessage, level) => {
        if(window.semaDebugMode) {
            switch(level) {
                case 'error':
                    console.error('[SIP] ' + traceMessage);
                    break;
                case 'info':
                    console.info('[SIP] ' + traceMessage);
                    break;
                case 'warn':
                    console.warn('[SIP] ' + traceMessage);
                    break;
                default:
                    console.log('[SIP] ' + traceMessage);
            }
        }
    };

    /**
     *
     */
    utils.getSettings = (callback) => {
        $.ajax({
            url: '/api/settings',
            success: function(data) {
                callback(data);
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.requestSensorState = (sensor) => {
        var promise = new Promise((resolve, reject) => {
            $.ajax({
                url: '/api/' + sensor,
                success: (data) => {
                    resolve(data);
                },
                error: (err) => {
                    console.log(`Error requesting sensor ${sensor} failed: ${err}`);
                    reject(err);
                },
                cache: false
            });
        });
        return promise;
    };

    /**
     *
     */
    utils.requestSensorData = (endpoint, chart, callback) => {
        utils.log('Calling to ' + endpoint);

        // "Sanitize" the input
        if(endpoint.charAt(0) === '/') {
            endpoint = endpoint.slice(1);
        }

        $.ajax({
            url: endpoint,
            success: function(data) {
                var series = chart.series[0],
                    shift = series.data.length > 20;

                // add the points
                for(let i=0; i<data.lastValues.length; i++) {
                    chart.series[0].addPoint(data.lastValues[i], true, shift);
                }

                callback();
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.sendX10Command = (device, action, callback) => {
        $.ajax({
            type: 'post',
            url: remoteUrl + '/x10',
            data: {
                device: device,
                action: action
            },
            success: function() {
                callback();
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.getSongList = (callback) => {
        $.ajax({
            url: remoteUrl + '/library',
            success: function(data) {
                callback(data);
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.playSong = (song) => {
        $.ajax({
            type: 'post',
            data: { song: song },
            url: remoteUrl + '/library/play',
            success: function() { },
            error: function() {
                // Check if there was an error (erro handler)
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.stopPlaying = () => {
        $.ajax({
            url: remoteUrl + '/library/stop',
            success: function(data) {
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.forwardPlaying = () => {
        $.ajax({
            url: remoteUrl + '/library/forward',
            success: function(data) {
            },
            cache: false
        });
    };

    /**
     *
     */
    utils.connectToBulb = () => {
        if(navigator.bluetooth) {
            navigator.bluetooth.requestDevice({
                filters: [{ services: [0xffe5] }]
            })
            .then(function(device) {
                // Step 2: Connect to it
                console.log('setp2: ', device);
                return device.gatt.connect();
            })
            .then(function(server) {
                // Step 3: Get the Service
                console.log('setp3: ', server);
                return server.getPrimaryService(0xffe5);
            })
            .then(function(service) {
                // Step 4: get the Characteristic
                console.log('setp4: ', service);
                return service.getCharacteristic(0xffe9);
            })
            .then(function(characteristic) {
                // Step 5: Write to the characteristic
                console.log('setp5: ', characteristic);
                ledCharacteristic = characteristic;
                var data = new Uint8Array([0xbb, 0x25, 0x05, 0x44]);
                return characteristic.writeValue(data);
            })
            .catch(function(error) {
                // And of course: error handling!
                console.error('Connection failed! ', error);
            });
        } else {
            alert('Error, bluetooth not supported or disconnected');
        }
    };

    /**
     *
     */
    utils.setBulbColor = (r, g, b) => {
        let data = new Uint8Array([0x56, r, g, b, 0x00, 0xf0, 0xaa]);
        return ledCharacteristic.writeValue(data)
            .catch(err => console.log('Error when writing value! ', err));
    };

    /**
     *
     */
    utils.turnOn = () => {
        let data = new Uint8Array([0xcc, 0x23, 0x33]);
        return ledCharacteristic.writeValue(data)
            .then(() => {})
            .catch(err => console.log('Error when turning on! ', err));
    }

    /**
     *
     */
    utils.turnOff = () => {
        let data = new Uint8Array([0xcc, 0x24, 0x33]);
        return ledCharacteristic.writeValue(data)
            .then(() => {})
            .catch(err => console.log('Error when turning off! ', err));
    }

    return utils;
}($));
<|endoftext|>


<commit_before>enyo.kind({
    name: "moon.MovieImageItem",
    classes: "moon-movie-list-item moon-3h moon-2v",
    spotlight: true,
    published: {
        option: {
            src: "",
            caption: ""
        }
    },
    handlers: {
        onSpotlightFocused: "focused",
        onSpotlightBlur: "released"
    },
    components: [
        {name: "caption", classes: "moon-movie-list-item-text"}
    ],
    create: function() {
        this.inherited(arguments);
        this.optionChanged();
    },
    getCaption: function() {
        return this.$.caption;
    },
    optionChanged: function(inOld) {
        this.applyStyle("background-image", 'url(' + this.option.src + ')');
        this.$.caption.setContent(this.option.caption);
    },
    focused: function() {
        this.$.caption.addClass("spotlight");
        return true;
    },
    released: function() {
        this.$.caption.removeClass("spotlight");
        return true;
    }
});

enyo.kind({
    name: "moon.ContextualLoginPopup",
    kind: "moon.ContextualPopup",
    classes: "moon-5h moon-3v",
    components: [
        {kind: "moon.Divider", content: "Log in to Service"},
        {kind: "moon.InputDecorator", spotlight: true, components: [
            {kind: "moon.Input", placeholder: "E-mail", onchange:""}
        ]},
        {kind: "moon.InputDecorator", spotlight: true, components: [
            {kind: "moon.Input", placeholder: "Password", onchange:""}
        ]},
        //{kind: "moon.CheckboxItem", content: "Log in setting Menu", checked: true, onchange: ""},
        {content: "Log in setting Menu"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "Log in"},
        {content: "or Connected with"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "FACEBOOK"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "TWITTER"}
    ]
});

// Sample view

enyo.kind({
    name: "moon.sample.login.ContextualPopupSample",
    kind: "moon.Panels",
    components: [
		{
            title: "Main Menu",
            components: [
                {
                    name: "menuList",
                    kind: "enyo.DataList",
                    scrollerOptions: { kind:"moon.Scroller"},
                    components: [
                        {bindFrom: "menuItem", kind: "moon.Item", ontap: "changePanel"}
                    ]
                }
            ]
        },
        {
            joinToPrev: true,
            layoutkind: "FittableRowsLayout",
            components: [
                {
                    name: "contentList",
                    kind: "enyo.DataGridList",
                    components: [
                        {kind: "moon.MovieImageItem", bindFrom: "itemOption", bindTo: "option"},
                    ]
                },
                {
                    name: "buttonList",
                    layoutkind: "FittableRowsLayout",
                    fit: true,
                    components: [
                        {kind: "moon.ContextualPopupDecorator", components: [
                            {kind: "moon.ContextualPopupButton", classes: "moon-2h", components: [
                                {tag: "img", attributes: {src: "assets/icon-half-like.png"}},
                                {content: "LIKE"}
                            ]},
                            {kind: "moon.ContextualLoginPopup"}
                        ]},
                        {kind: "moon.ContextualPopupDecorator", components: [
                            {classes: "moon-2h", content: "SHARE"},
                            {kind: "moon.ContextualLoginPopup"}
                        ]},
                    ]
                }
            ]
        }
    ],
    bindings: [
        {from: ".controller.menus", to: "$.menuList.controller"},
        {from: ".controller.contents", to: "$.contentList.controller"}
    ]
 });

// Sample model

enyo.ready(function(){
    var sampleModel = new enyo.Model({
        menus: new enyo.Collection([
            {menuItem: "Browser Movies"},
            {menuItem: "Browser TV Shows"},
            {menuItem: "Queue"},
            {menuItem: "Search"}
        ]),
        contents: new enyo.Collection([
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}}
        ])
    });

//  Application to render sample

    new enyo.Application({
        view: {
            classes: "enyo-unselectable moon",
            components: [
                {kind: "enyo.Spotlight"},
                {
                    kind: "moon.sample.login.ContextualPopupSample",
                    controller: ".app.controllers.movieController",
                    classes: "enyo-fit"
                }
            ]
        },
        controllers: [
            {
                name: "movieController",
                kind: "enyo.ModelController",
                model: sampleModel,
                changePanel: function(inSender, inEvent) {
                    enyo.log("Item: " + inEvent.originator.parent.controller.model.get("menuItem"));
                }
            }
        ]
    });
})<commit_msg>Remove trailing comma on Login ContextualPopupSample<commit_after>enyo.kind({
    name: "moon.MovieImageItem",
    classes: "moon-movie-list-item moon-3h moon-2v",
    spotlight: true,
    published: {
        option: {
            src: "",
            caption: ""
        }
    },
    handlers: {
        onSpotlightFocused: "focused",
        onSpotlightBlur: "released"
    },
    components: [
        {name: "caption", classes: "moon-movie-list-item-text"}
    ],
    create: function() {
        this.inherited(arguments);
        this.optionChanged();
    },
    getCaption: function() {
        return this.$.caption;
    },
    optionChanged: function(inOld) {
        this.applyStyle("background-image", 'url(' + this.option.src + ')');
        this.$.caption.setContent(this.option.caption);
    },
    focused: function() {
        this.$.caption.addClass("spotlight");
        return true;
    },
    released: function() {
        this.$.caption.removeClass("spotlight");
        return true;
    }
});

enyo.kind({
    name: "moon.ContextualLoginPopup",
    kind: "moon.ContextualPopup",
    classes: "moon-5h moon-3v",
    components: [
        {kind: "moon.Divider", content: "Log in to Service"},
        {kind: "moon.InputDecorator", spotlight: true, components: [
            {kind: "moon.Input", placeholder: "E-mail", onchange:""}
        ]},
        {kind: "moon.InputDecorator", spotlight: true, components: [
            {kind: "moon.Input", placeholder: "Password", onchange:""}
        ]},
        {content: "Log in setting Menu"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "Log in"},
        {content: "or Connected with"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "FACEBOOK"},
        {kind: "moon.Button", classes: "moon-light-gray", content: "TWITTER"}
    ]
});

// Sample view

enyo.kind({
    name: "moon.sample.login.ContextualPopupSample",
    kind: "moon.Panels",
    components: [
		{
            title: "Main Menu",
            components: [
                {
                    name: "menuList",
                    kind: "enyo.DataList",
                    scrollerOptions: { kind:"moon.Scroller"},
                    components: [
                        {bindFrom: "menuItem", kind: "moon.Item", ontap: "changePanel"}
                    ]
                }
            ]
        },
        {
            joinToPrev: true,
            layoutkind: "FittableRowsLayout",
            components: [
                {
                    name: "contentList",
                    kind: "enyo.DataGridList",
                    components: [
                        {kind: "moon.MovieImageItem", bindFrom: "itemOption", bindTo: "option"}
                    ]
                },
                {
                    name: "buttonList",
                    layoutkind: "FittableRowsLayout",
                    fit: true,
                    components: [
                        {kind: "moon.ContextualPopupDecorator", components: [
                            {kind: "moon.ContextualPopupButton", classes: "moon-2h", components: [
                                {tag: "img", attributes: {src: "assets/icon-half-like.png"}},
                                {content: "LIKE"}
                            ]},
                            {kind: "moon.ContextualLoginPopup"}
                        ]},
                        {kind: "moon.ContextualPopupDecorator", components: [
                            {classes: "moon-2h", content: "SHARE"},
                            {kind: "moon.ContextualLoginPopup"}
                        ]}
                    ]
                }
            ]
        }
    ],
    bindings: [
        {from: ".controller.menus", to: "$.menuList.controller"},
        {from: ".controller.contents", to: "$.contentList.controller"}
    ]
 });

// Sample model

enyo.ready(function(){
    var sampleModel = new enyo.Model({
        menus: new enyo.Collection([
            {menuItem: "Browser Movies"},
            {menuItem: "Browser TV Shows"},
            {menuItem: "Queue"},
            {menuItem: "Search"}
        ]),
        contents: new enyo.Collection([
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}},
            {itemOption: {src: "assets/default-movie-vertical.png"}}
        ])
    });

//  Application to render sample

    new enyo.Application({
        view: {
            classes: "enyo-unselectable moon",
            components: [
                {kind: "enyo.Spotlight"},
                {
                    kind: "moon.sample.login.ContextualPopupSample",
                    controller: ".app.controllers.movieController",
                    classes: "enyo-fit"
                }
            ]
        },
        controllers: [
            {
                name: "movieController",
                kind: "enyo.ModelController",
                model: sampleModel,
                changePanel: function(inSender, inEvent) {
                    enyo.log("Item: " + inEvent.originator.parent.controller.model.get("menuItem"));
                }
            }
        ]
    });
});<|endoftext|>