<commit_before>function OkkChatReady(OkkChatApi) {

/***********************************************/
/* Example of Server API class with dispatcher */
/***********************************************/
    var IncomingSoundManager = objectAssign({}, {
        _audio: null,
        _mute: false,
        _hasError: false,
        mute: function(){
            this._mute = true;
        },
        unmute: function(){
            this._mute = false;
        },
        _onerror: function(){
            this._hasError = true;
        },
        hasError: function(){
            return this._hasError;
        },
        play: function(){
            var url = ChatConfig.INCOMING_MESSAGE_SOUND_PATH || null;
            if(!this._audio && url){
                this._audio = new Audio();
                this._audio.onerror = this._onerror;
                this._audio.src = url;
            }
            if(this._audio && !this.hasError() && !this._mute){
                this._audio.play();
            }
        }
    });

    var ServerAPI = objectAssign({}, {
        _loadQueue: {},
        _accessKey: null,
        _socket: null,
        _firstConnection: true,
        _connectToSocket: function(){
            var self = this,
                opts = {
                    path: ChatConfig.SOCKET_IO_NS
                };

            if(this._accessKey){
                opts['extraHeaders'] = {'Authorization': this._accessKey};
            }

            var socket = io(ChatConfig.SOCKET_IO_URL, opts);

            socket.on('connect', function(){
                console.log('connected!!!');
                self._socket = socket;
                OkkChatApi.Actions.operatorStatusChanged(OkkChatApi.ContactStatus.ONLINE);
                if(!ServerAPI._firstConnection){
                    ServerAPI.loadContacts(ServerAPI.loadNewestMessagesForCurrentContact);
                }
                ServerAPI._firstConnection = false;
            });

            socket.on('disconnect', function(){
                console.log('disconnect!!!');
                OkkChatApi.Actions.operatorStatusChanged(OkkChatApi.ContactStatus.OFFLINE);
                OkkChatApi.Stores.ContactsStore.makeAllOffline();
            });

            socket.on('incoming:message', function (response, sendAck) {
                var message = JSON.parse(response);
                if(typeof sendAck == 'function'){
                    var currentOperator = OkkChatApi.Stores.AuthStore.getOperator();
                    sendAck(JSON.stringify({id:+message.id, deliveredTo: currentOperator.nick}));
                }
                OkkChatApi.Actions.incomingMessage(message);
            });

            socket.on('client:status', function (data) {
                var client = JSON.parse(data);
                OkkChatApi.Actions.clientStatusChanged(client.id, client.username, client.status);
            });

            socket.on('client:new', function (response) {

            });
        },
        pushQueue: function(contactId){
            if(!this._loadQueue[contactId]){
                this._loadQueue[contactId] = true;
                return true;
            }
            return false;
        },
        popQueue: function(contactId){
            delete this._loadQueue[contactId];
        },
        authenticate: function () {
            fetch(ChatConfig.URL_TO_OPERATOR_AUTH, { credentials: 'include' })
            .then(function(response){
                return response.json();
            })
            .then(function(data){
                if(data.success) {
                    ServerAPI._accessKey = data.access_key;
                    setTimeout(function() {
                        var user = data.user;
                        var operator = {
                            id: user.id,
                            name: user.first_name,
                            nick: user.username,
                            status: OkkChatApi.ContactStatus.ONLINE
                        };
                        OkkChatApi.Actions.authSuccess(operator);
                        ServerAPI._connectToSocket();
                    }, 1000);
                }else{
                    setTimeout(function(){
                        OkkChatApi.Actions.authFail(data.message);
                    }, 1000);
                }
            })
            .catch(function(data){
                    setTimeout(function(){
                        OkkChatApi.Actions.authFail(data.message);
                    }, 1000);
            });
        },
        loadContacts: function (cb) {
            this._socket.emit('client:list', {}, function (jsonResponse) {
                var response = JSON.parse(jsonResponse);
                if(response.success) {
                    OkkChatApi.Stores.ContactsStore.init(response.data);
                    OkkChatApi.Stores.ContactsStore.emitChange();
                    OkkChatApi.Stores.MessageStore.init(response.unread)
                }
                if(typeof cb == "function") {
                    cb();
                }
            });
        },

        loadNewestMessagesForCurrentContact: function(){
            var contact =  OkkChatApi.Stores.ContactsStore.getCurrentContact();
            var lastMsgId = null;
            if(contact) {
                var unsentMessages = OkkChatApi.Stores.MessageStore.getUnsentMessages(contact.name);
                if(unsentMessages && !unsentMessages.length) {
                    lastMsgId = OkkChatApi.Stores.MessageStore.getLastDeliveredMessageId(contact.name);
                    ServerAPI.loadNewestRawContactMessages(contact.name, lastMsgId);
                }else{
                    lastMsgId = OkkChatApi.Stores.MessageStore.getLastDeliveredMessageId(contact.name);
                    ServerAPI.loadNewestRawContactMessages(contact.name, lastMsgId);
                }
            }
        },

        checkUnreadMessages: function(unsentMessages, cb){
            if(unsentMessages && unsentMessages.length) {
                ServerAPI._socket.emit('operator:check:messages', JSON.stringify(unsentMessages), cb);
            }
        },

        sendReadEvent: function(unreadIds){
            var data = ServerAPI.getNormalizedUnreadIds(unreadIds);
            if(data.messageIds.length) {
                ServerAPI._socket.emit('operator:read:messages', JSON.stringify(data), function(data){});
            }
        },

        loadRawContactMessages: function (contactId, firstMsgId) {
            var queryData = {mobile: contactId};
            if (firstMsgId){
                queryData['firstMessageId'] = firstMsgId;
            }

            this._socket.emit('operator:message:history', JSON.stringify(queryData), function(data){
                var response = JSON.parse(data);
                if(response.success) {
                    var operator = OkkChatApi.Stores.AuthStore.getOperator();
                    var unreadIds = OkkChatApi.Stores.MessageStore.addContactRawMessages(operator,
                        response.contact,
                        response.data);
                    OkkChatApi.Stores.MessageStore.emitUpdate();
                    OkkChatApi.Stores.ContactsStore.setLoadedState(response.contact);
                    OkkChatApi.Stores.ContactsStore.emitContactSelect();
                    ServerAPI.popQueue(response.contact);
                    this.sendReadEvent(unreadIds);
                    OkkChatApi.Stores.MessageStore.clearUnreadMessages(response.contact);
                }
            }.bind(this));
        },
        loadNewestRawContactMessages: function (contactId, lastMsgId) {
            var queryData = {mobile: contactId};
            if (lastMsgId){
                queryData['lastMessageId'] = lastMsgId;
            }

            this._socket.emit('operator:newest:message:history', JSON.stringify(queryData), function(jsonData){
                var history = JSON.parse(jsonData);
                var unreadIds = [];
                if(!history.success) {
                    return;
                }
                var newMessages = [];
                var operator = OkkChatApi.Stores.AuthStore.getOperator();
                var historyData = history.data;
                for(var i=0, len=historyData.length; i<len; i++){
                    var message = historyData[i];
                    var updateFlag = OkkChatApi.Stores.MessageStore._updateExisted(contactId, message);
                    if(updateFlag == OkkChatApi.ChatMessageUpdateStatus.NOT_UPDATED){
                        unreadIds.push(message.id);
                        newMessages.push(message);
                    }
                    if(updateFlag == OkkChatApi.ChatMessageUpdateStatus.UPDATED_WITH_TEMP_ID) {
                        OkkChatApi.Stores.MessageStore._unregisterOutMessage(history.contact, message.tempId);
                    }
                }
                OkkChatApi.Stores.MessageStore.addContactRawMessages(operator, history.contact, newMessages, true);
                data = ServerAPI.getNormalizedUnreadIds(unreadIds);

                var unsentMessages = OkkChatApi.Stores.MessageStore.getUnsentMessages(history.contact);
                for(var mIndex=0, lenUnsent=unsentMessages.length; mIndex<lenUnsent; mIndex++) {
                    ServerAPI.sendMessageToServer(unsentMessages[mIndex]);
                }

                if(data.messageIds.length) {
                    ServerAPI._socket.emit('operator:read:messages', JSON.stringify(data), function(data){});
                }
                ServerAPI.popQueue(history.contact);
            });
        },
        sendMessageToServer: function(msg){
            this._socket.emit('operator:message', JSON.stringify(msg), function(response){
                 var res = JSON.parse(response);
                 OkkChatApi.Actions.updateMessageContent(this.receiver, res.temp_id, res);
            }.bind(msg));
        },
        getNormalizedUnreadIds: function(unreadIds){
            if(unreadIds && unreadIds.length){
                var unreadedMsgIds = [];
                for(var i=0; i<unreadIds.length; i++){
                    if(+unreadIds[i]!=0) {
                        unreadedMsgIds.push(+unreadIds[i].replace(/m_/gi, ''))
                    }
                }
                return {messageIds:unreadedMsgIds};
            }
            return {messageIds:[]};
        }
    });

    ServerAPI.dispatchToken = OkkChatApi.Dispatcher.register(function (action) {
        var contactId,
            added = false;
        switch (action.type) {
            case OkkChatApi.ActionTypes.NEW_OUT_MESSAGE:
                var msg = action.payload;
                var rawMessage = {
                    id: msg.id,
                    message: msg.contentType == OkkChatApi.MessageContentTypes.IMAGE ? msg.fullImage : msg.message,
                    sender: msg.sender,
                    receiver: msg.receiver,
                    contentType: msg.contentType,
                    messageType: msg.messageType,
                    date: OkkChatApi.CoreUtils.formatDate(msg.date),
                    endOfConversation: msg.endOfConversation,
                    operator: true
                };
                ServerAPI.sendMessageToServer(rawMessage);
                break;
            case OkkChatApi.ActionTypes.API_FETCH_CONTACTS:
                ServerAPI.loadContacts();
                break;
            case OkkChatApi.ActionTypes.API_AUTH_OPERATOR:
                ServerAPI.authenticate(action.credentials);
                break;
            case OkkChatApi.ActionTypes.API_FETCH_CONTACT_HISTORY:
                contactId = action.contact.name;
                added = ServerAPI.pushQueue(contactId);
                if(added) {
                    ServerAPI.loadRawContactMessages(contactId, action.firstMessageId);
                }
                break;
            case OkkChatApi.ActionTypes.API_FETCH_NEWEST_CONTACT_HISTORY:
                contactId = action.contact.name;
                added = ServerAPI.pushQueue(contactId);
                if(added) {
                    ServerAPI.loadNewestRawContactMessages(contactId, action.lastMessageId);
                }
                break;
            case OkkChatApi.ActionTypes.NEW_IN_MESSAGE:
                IncomingSoundManager.play();
                var contact = OkkChatApi.Stores.ContactsStore.getCurrentContact();
                var msg = action.payload;
                if(msg.sender == contact.name) {
                    ServerAPI.sendReadEvent([msg.id]);
                }
                break;
            case OkkChatApi.ActionTypes.MUTE_NOTIFICATION_SOUND:
                IncomingSoundManager.mute();
                break;
            case OkkChatApi.ActionTypes.UNMUTE_NOTIFICATION_SOUND:
                IncomingSoundManager.unmute();
                break;
            case OkkChatApi.ActionTypes.READ_MESSAGES:
                var unreadIds = OkkChatApi.Stores.UnreadMessageStore.getUnreadIds(action.contactId);
                ServerAPI.sendReadEvent(unreadIds);
                OkkChatApi.Stores.MessageStore.clearUnreadMessages(action.contactId);
                break;
            default:
                break;
        }
    });
}<commit_msg>ChatApi: Fixed error when no current contact found<commit_after>function OkkChatReady(OkkChatApi) {

/***********************************************/
/* Example of Server API class with dispatcher */
/***********************************************/
    var IncomingSoundManager = objectAssign({}, {
        _audio: null,
        _mute: false,
        _hasError: false,
        mute: function(){
            this._mute = true;
        },
        unmute: function(){
            this._mute = false;
        },
        _onerror: function(){
            this._hasError = true;
        },
        hasError: function(){
            return this._hasError;
        },
        play: function(){
            var url = ChatConfig.INCOMING_MESSAGE_SOUND_PATH || null;
            if(!this._audio && url){
                this._audio = new Audio();
                this._audio.onerror = this._onerror;
                this._audio.src = url;
            }
            if(this._audio && !this.hasError() && !this._mute){
                this._audio.play();
            }
        }
    });

    var ServerAPI = objectAssign({}, {
        _loadQueue: {},
        _accessKey: null,
        _socket: null,
        _firstConnection: true,
        _connectToSocket: function(){
            var self = this,
                opts = {
                    path: ChatConfig.SOCKET_IO_NS
                };

            if(this._accessKey){
                opts['extraHeaders'] = {'Authorization': this._accessKey};
            }

            var socket = io(ChatConfig.SOCKET_IO_URL, opts);

            socket.on('connect', function(){
                console.log('connected!!!');
                self._socket = socket;
                OkkChatApi.Actions.operatorStatusChanged(OkkChatApi.ContactStatus.ONLINE);
                if(!ServerAPI._firstConnection){
                    ServerAPI.loadContacts(ServerAPI.loadNewestMessagesForCurrentContact);
                }
                ServerAPI._firstConnection = false;
            });

            socket.on('disconnect', function(){
                console.log('disconnect!!!');
                OkkChatApi.Actions.operatorStatusChanged(OkkChatApi.ContactStatus.OFFLINE);
                OkkChatApi.Stores.ContactsStore.makeAllOffline();
            });

            socket.on('incoming:message', function (response, sendAck) {
                var message = JSON.parse(response);
                if(typeof sendAck == 'function'){
                    var currentOperator = OkkChatApi.Stores.AuthStore.getOperator();
                    sendAck(JSON.stringify({id:+message.id, deliveredTo: currentOperator.nick}));
                }
                OkkChatApi.Actions.incomingMessage(message);
            });

            socket.on('client:status', function (data) {
                var client = JSON.parse(data);
                OkkChatApi.Actions.clientStatusChanged(client.id, client.username, client.status);
            });

            socket.on('client:new', function (response) {

            });
        },
        pushQueue: function(contactId){
            if(!this._loadQueue[contactId]){
                this._loadQueue[contactId] = true;
                return true;
            }
            return false;
        },
        popQueue: function(contactId){
            delete this._loadQueue[contactId];
        },
        authenticate: function () {
            fetch(ChatConfig.URL_TO_OPERATOR_AUTH, { credentials: 'include' })
            .then(function(response){
                return response.json();
            })
            .then(function(data){
                if(data.success) {
                    ServerAPI._accessKey = data.access_key;
                    setTimeout(function() {
                        var user = data.user;
                        var operator = {
                            id: user.id,
                            name: user.first_name,
                            nick: user.username,
                            status: OkkChatApi.ContactStatus.ONLINE
                        };
                        OkkChatApi.Actions.authSuccess(operator);
                        ServerAPI._connectToSocket();
                    }, 1000);
                }else{
                    setTimeout(function(){
                        OkkChatApi.Actions.authFail(data.message);
                    }, 1000);
                }
            })
            .catch(function(data){
                    setTimeout(function(){
                        OkkChatApi.Actions.authFail(data.message);
                    }, 1000);
            });
        },
        loadContacts: function (cb) {
            this._socket.emit('client:list', {}, function (jsonResponse) {
                var response = JSON.parse(jsonResponse);
                if(response.success) {
                    OkkChatApi.Stores.ContactsStore.init(response.data);
                    OkkChatApi.Stores.ContactsStore.emitChange();
                    OkkChatApi.Stores.MessageStore.init(response.unread)
                }
                if(typeof cb == "function") {
                    cb();
                }
            });
        },

        loadNewestMessagesForCurrentContact: function(){
            var contact =  OkkChatApi.Stores.ContactsStore.getCurrentContact();
            var lastMsgId = null;
            if(contact) {
                var unsentMessages = OkkChatApi.Stores.MessageStore.getUnsentMessages(contact.name);
                if(unsentMessages && !unsentMessages.length) {
                    lastMsgId = OkkChatApi.Stores.MessageStore.getLastDeliveredMessageId(contact.name);
                    ServerAPI.loadNewestRawContactMessages(contact.name, lastMsgId);
                }else{
                    lastMsgId = OkkChatApi.Stores.MessageStore.getLastDeliveredMessageId(contact.name);
                    ServerAPI.loadNewestRawContactMessages(contact.name, lastMsgId);
                }
            }
        },

        checkUnreadMessages: function(unsentMessages, cb){
            if(unsentMessages && unsentMessages.length) {
                ServerAPI._socket.emit('operator:check:messages', JSON.stringify(unsentMessages), cb);
            }
        },

        sendReadEvent: function(unreadIds){
            var data = ServerAPI.getNormalizedUnreadIds(unreadIds);
            if(data.messageIds.length) {
                ServerAPI._socket.emit('operator:read:messages', JSON.stringify(data), function(data){});
            }
        },

        loadRawContactMessages: function (contactId, firstMsgId) {
            var queryData = {mobile: contactId};
            if (firstMsgId){
                queryData['firstMessageId'] = firstMsgId;
            }

            this._socket.emit('operator:message:history', JSON.stringify(queryData), function(data){
                var response = JSON.parse(data);
                if(response.success) {
                    var operator = OkkChatApi.Stores.AuthStore.getOperator();
                    var unreadIds = OkkChatApi.Stores.MessageStore.addContactRawMessages(operator,
                        response.contact,
                        response.data);
                    OkkChatApi.Stores.MessageStore.emitUpdate();
                    OkkChatApi.Stores.ContactsStore.setLoadedState(response.contact);
                    OkkChatApi.Stores.ContactsStore.emitContactSelect();
                    ServerAPI.popQueue(response.contact);
                    this.sendReadEvent(unreadIds);
                    OkkChatApi.Stores.MessageStore.clearUnreadMessages(response.contact);
                }
            }.bind(this));
        },
        loadNewestRawContactMessages: function (contactId, lastMsgId) {
            var queryData = {mobile: contactId};
            if (lastMsgId){
                queryData['lastMessageId'] = lastMsgId;
            }

            this._socket.emit('operator:newest:message:history', JSON.stringify(queryData), function(jsonData){
                var history = JSON.parse(jsonData);
                var unreadIds = [];
                if(!history.success) {
                    return;
                }
                var newMessages = [];
                var operator = OkkChatApi.Stores.AuthStore.getOperator();
                var historyData = history.data;
                for(var i=0, len=historyData.length; i<len; i++){
                    var message = historyData[i];
                    var updateFlag = OkkChatApi.Stores.MessageStore._updateExisted(contactId, message);
                    if(updateFlag == OkkChatApi.ChatMessageUpdateStatus.NOT_UPDATED){
                        unreadIds.push(message.id);
                        newMessages.push(message);
                    }
                    if(updateFlag == OkkChatApi.ChatMessageUpdateStatus.UPDATED_WITH_TEMP_ID) {
                        OkkChatApi.Stores.MessageStore._unregisterOutMessage(history.contact, message.tempId);
                    }
                }
                OkkChatApi.Stores.MessageStore.addContactRawMessages(operator, history.contact, newMessages, true);
                data = ServerAPI.getNormalizedUnreadIds(unreadIds);

                var unsentMessages = OkkChatApi.Stores.MessageStore.getUnsentMessages(history.contact);
                for(var mIndex=0, lenUnsent=unsentMessages.length; mIndex<lenUnsent; mIndex++) {
                    ServerAPI.sendMessageToServer(unsentMessages[mIndex]);
                }

                if(data.messageIds.length) {
                    ServerAPI._socket.emit('operator:read:messages', JSON.stringify(data), function(data){});
                }
                ServerAPI.popQueue(history.contact);
            });
        },
        sendMessageToServer: function(msg){
            this._socket.emit('operator:message', JSON.stringify(msg), function(response){
                 var res = JSON.parse(response);
                 OkkChatApi.Actions.updateMessageContent(this.receiver, res.temp_id, res);
            }.bind(msg));
        },
        getNormalizedUnreadIds: function(unreadIds){
            if(unreadIds && unreadIds.length){
                var unreadedMsgIds = [];
                for(var i=0; i<unreadIds.length; i++){
                    if(+unreadIds[i]!=0) {
                        unreadedMsgIds.push(+unreadIds[i].replace(/m_/gi, ''))
                    }
                }
                return {messageIds:unreadedMsgIds};
            }
            return {messageIds:[]};
        }
    });

    ServerAPI.dispatchToken = OkkChatApi.Dispatcher.register(function (action) {
        var contactId,
            added = false;
        switch (action.type) {
            case OkkChatApi.ActionTypes.NEW_OUT_MESSAGE:
                var msg = action.payload;
                var rawMessage = {
                    id: msg.id,
                    message: msg.contentType == OkkChatApi.MessageContentTypes.IMAGE ? msg.fullImage : msg.message,
                    sender: msg.sender,
                    receiver: msg.receiver,
                    contentType: msg.contentType,
                    messageType: msg.messageType,
                    date: OkkChatApi.CoreUtils.formatDate(msg.date),
                    endOfConversation: msg.endOfConversation,
                    operator: true
                };
                ServerAPI.sendMessageToServer(rawMessage);
                break;
            case OkkChatApi.ActionTypes.API_FETCH_CONTACTS:
                ServerAPI.loadContacts();
                break;
            case OkkChatApi.ActionTypes.API_AUTH_OPERATOR:
                ServerAPI.authenticate(action.credentials);
                break;
            case OkkChatApi.ActionTypes.API_FETCH_CONTACT_HISTORY:
                contactId = action.contact.name;
                added = ServerAPI.pushQueue(contactId);
                if(added) {
                    ServerAPI.loadRawContactMessages(contactId, action.firstMessageId);
                }
                break;
            case OkkChatApi.ActionTypes.API_FETCH_NEWEST_CONTACT_HISTORY:
                contactId = action.contact.name;
                added = ServerAPI.pushQueue(contactId);
                if(added) {
                    ServerAPI.loadNewestRawContactMessages(contactId, action.lastMessageId);
                }
                break;
            case OkkChatApi.ActionTypes.NEW_IN_MESSAGE:
                IncomingSoundManager.play();
                var contact = OkkChatApi.Stores.ContactsStore.getCurrentContact();
                var msg = action.payload;
                if(contact && msg.sender == contact.name) {
                    ServerAPI.sendReadEvent([msg.id]);
                }
                break;
            case OkkChatApi.ActionTypes.MUTE_NOTIFICATION_SOUND:
                IncomingSoundManager.mute();
                break;
            case OkkChatApi.ActionTypes.UNMUTE_NOTIFICATION_SOUND:
                IncomingSoundManager.unmute();
                break;
            case OkkChatApi.ActionTypes.READ_MESSAGES:
                var unreadIds = OkkChatApi.Stores.UnreadMessageStore.getUnreadIds(action.contactId);
                ServerAPI.sendReadEvent(unreadIds);
                OkkChatApi.Stores.MessageStore.clearUnreadMessages(action.contactId);
                break;
            default:
                break;
        }
    });
}<|endoftext|>


<commit_before>/**
 * Part of the evias/pacNEM package.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under MIT License.
 *
 * This source file is subject to the MIT License that is
 * bundled with this package in the LICENSE file.
 *
 * @package    evias/pacNEM
 * @author     Grégory Saive <greg@evias.be> (https://github.com/evias)
 * @contributor Nicolas Dubien (https://github.com/dubzzz)
 * @license    MIT License
 * @copyright  (c) 2017, Grégory Saive <greg@evias.be>
 * @link       https://github.com/evias/pacNEM
 */

(function() {

var config = require("config"),
    path = require('path');

var __smartfilename = path.basename(__filename);
var NEMBot_for_pacNEM = {
    "paymentBot": {host: process.env["PAYMENT_BOT_HOST"] || config.get("pacnem.bots.paymentBot")}
};

var botChannelSockets_ = {};

/**
 * class PaymentsCore provides a business layer for
 * payments management features. (Invoices, Payment updates, etc.)
 *
 * @author  Grégory Saive <greg@evias.be> (https://github.com/evias)
 */
var PaymentsCore = function(io, logger, chainDataLayer, dataLayer)
{
    this.socketIO_ = io;
    this.blockchain_ = chainDataLayer;
    this.db_ = dataLayer;

    this.logger_ = logger;

    /**
     * The startPaymentChannel function is used to open the communication
     * channel between this backend and the NEMBot responsible for Payment
     * Processing of the pacNEM game invoices.
     *
     * This function will emit `pacnem_payment_status_update` to `clientSocketId`
     * in case the NEMBot sends a payment update to this backend (through
     * the previously created communication channel).
     *
     * @param  {NEMPaymentChannel}   invoice
     * @param  {string}   clientSocketId  - Frontend SocketIO socket ID (Frontend to Backend communication)
     * @param  {Function} callback       [description]
     * @return {void}
     */
    this.startPaymentChannel = function(invoice, clientSocketId, callback)
    {
        var self = this;
        // Now the BACKEND will subscribe to a direct channel to the NEMBot responsible
        // for Payment Reception Listening. Here we will link the BACKEND SOCKET ID
        // with the CLIENT SOCKET ID. The client should never request directly to the
        // NEMBot, so we proxy the whole event chain to avoid this.

        // First we emit a `nembot_open_payment_channel` with the given invoice NUMBER and payer XEM address.
        // Then we register a listener on `nembot_payment_status_update` which will be triggered when a
        // Transaction with MESSAGE being the invoiceNumber OR SENDER PUBLIC KEY being the payerXEM, is received
        // (/unconfirmed &  /transactions). When the transaction is included in a block, another event will be
        // will be triggered (`nembot_payment_status_update` again) with status `completed`, this time.
        // Only the second call with completed status should be trusted as a paid amount for the invoice.

        var socket = require("socket.io-client");
        var channelSocket = socket.connect(NEMBot_for_pacNEM.paymentBot.host);
        var channelParams = {
            message: invoice.number,
            sender: invoice.payerXEM,
            recipient: invoice.recipientXEM,
            amount: invoice.amount,
            maxDuration: 5 * 60 * 1000
        };

        self.logger_.info(__smartfilename, __line, '[BOT] open_channel(' + JSON.stringify(channelParams) + ') with NEMBot host: ' + NEMBot_for_pacNEM.paymentBot.host);
        channelSocket.emit("nembot_open_payment_channel", JSON.stringify(channelParams));

        // configure payment status update event FORWARDING (comes from NEMBot and forwards to Frontend)
        channelSocket.on("nembot_payment_status_update", function(rawdata)
            {
                self.logger_.info(__smartfilename, __line, '[' + channelSocket.id + '] [BOT] nembot_payment_status_update(' + rawdata + ')');

                var data = JSON.parse(rawdata);

                // forward to client..
                var clientData = {
                    status: data.status,
                    paymentData: data
                };
                io.sockets.to(clientSocketId)
                  .emit("pacnem_payment_status_update", JSON.stringify(clientData));

                // do the UI magic
                self.storeInvoiceStatusUpdate(data);
            });

        // save new backend socket ID to invoice.
        if (! invoice.socketIds || ! invoice.socketIds.length)
            invoice.socketIds = [channelSocket.id];
        else {
            var sockets = invoice.socketIds;
            sockets.push(channelSocket.id);

            invoice.socketIds = sockets;
        }

        if (! botChannelSockets_.hasOwnProperty(invoice.number))
            botChannelSockets_[invoice.number] = [];

        botChannelSockets_[invoice.number].push({socket: channelSocket, clientId: clientSocketId});

        invoice.save(function(err)
            {
                callback(invoice);
            });
    };

    /**
     * This function saves an invoice status update to the
     * database. It helps keeping track of the payment states.
     *
     * When the data is saved to the database, a custom callback
     * will be executed to send a transaction using our pacNEM
     * Multi Signature Account so that the the buyer receives
     * the bought evias.pacnem:heart Mosaics.
     *
     * @param  {object} data
     * @return {void}
     */
    this.storeInvoiceStatusUpdate = function(data)
    {
        var self = this;
        var invoiceQuery = {};

        if (typeof data.message != 'undefined' && data.message.length) {
            // Player sent message along with transaction.
            invoiceQuery["number"] = data.message;
        }
        else if (typeof data.sender != 'undefined' && data.sender.length) {
            // Player didn't send a Message with the transaction..
            invoiceQuery["payerXEM"] = data.sender;
        }

        //DEBUG self.logger_.info("[PACNEM] [INVOICE]", "[DEBUG]", 'Fetching invoice with: ' + JSON.stringify(data));

        // find invoice and update status and amounts
        self.db_.NEMPaymentChannel.findOne(invoiceQuery, function(err, invoice)
        {
            if (! err && invoice) {
                invoice.status = data.status;

                if (data.status == "unconfirmed")
                    invoice.amountUnconfirmed = data.amountUnconfirmed;
                else if (data.amountPaid)
                    invoice.amountPaid = data.amountPaid;

                if (data.status == "paid") {
                    invoice.isPaid = true;
                    invoice.paidAt = new Date().valueOf();
                }

                invoice.save(function(err)
                {
                    if (err) {
                        self.logger_.error(__smartfilename, __line, '[ERROR] Invoice status update error: ' + err);
                        return false;
                    }

                    if (data.status == "paid" && invoice.isPaid === true) {
                        self.closePaymentChannel(invoice);
                    }
                });
            }
        });
    }

    this.closePaymentChannel = function(paymentChannel)
    {
        var self = this;
        self.blockchain_.sendHeartsForPayment(paymentChannel, function(paymentChannel)
        {
            // forward "DONE PAYMENT" to client..
            var clientData = {
                status: paymentChannel.status,
                number: paymentChannel.number
            };

            if (botChannelSockets_.hasOwnProperty(paymentChannel.number)) {
                //var clientSocketId = botChannelSockets_[paymentChannel.number].clientId;
                var socketsForPayment = botChannelSockets_[paymentChannel.number];

                for (var i in socketsForPayment)
                    self.socketIO_.sockets.to(socketsForPayments[i].clientId)
                        .emit("pacnem_payment_success", JSON.stringify(clientData));
            }
        });
    };

};

module.exports.PaymentsCore = PaymentsCore;
}());
<commit_msg>hotfix variable typo<commit_after>/**
 * Part of the evias/pacNEM package.
 *
 * NOTICE OF LICENSE
 *
 * Licensed under MIT License.
 *
 * This source file is subject to the MIT License that is
 * bundled with this package in the LICENSE file.
 *
 * @package    evias/pacNEM
 * @author     Grégory Saive <greg@evias.be> (https://github.com/evias)
 * @contributor Nicolas Dubien (https://github.com/dubzzz)
 * @license    MIT License
 * @copyright  (c) 2017, Grégory Saive <greg@evias.be>
 * @link       https://github.com/evias/pacNEM
 */

(function() {

var config = require("config"),
    path = require('path');

var __smartfilename = path.basename(__filename);
var NEMBot_for_pacNEM = {
    "paymentBot": {host: process.env["PAYMENT_BOT_HOST"] || config.get("pacnem.bots.paymentBot")}
};

var botChannelSockets_ = {};

/**
 * class PaymentsCore provides a business layer for
 * payments management features. (Invoices, Payment updates, etc.)
 *
 * @author  Grégory Saive <greg@evias.be> (https://github.com/evias)
 */
var PaymentsCore = function(io, logger, chainDataLayer, dataLayer)
{
    this.socketIO_ = io;
    this.blockchain_ = chainDataLayer;
    this.db_ = dataLayer;

    this.logger_ = logger;

    /**
     * The startPaymentChannel function is used to open the communication
     * channel between this backend and the NEMBot responsible for Payment
     * Processing of the pacNEM game invoices.
     *
     * This function will emit `pacnem_payment_status_update` to `clientSocketId`
     * in case the NEMBot sends a payment update to this backend (through
     * the previously created communication channel).
     *
     * @param  {NEMPaymentChannel}   invoice
     * @param  {string}   clientSocketId  - Frontend SocketIO socket ID (Frontend to Backend communication)
     * @param  {Function} callback       [description]
     * @return {void}
     */
    this.startPaymentChannel = function(invoice, clientSocketId, callback)
    {
        var self = this;
        // Now the BACKEND will subscribe to a direct channel to the NEMBot responsible
        // for Payment Reception Listening. Here we will link the BACKEND SOCKET ID
        // with the CLIENT SOCKET ID. The client should never request directly to the
        // NEMBot, so we proxy the whole event chain to avoid this.

        // First we emit a `nembot_open_payment_channel` with the given invoice NUMBER and payer XEM address.
        // Then we register a listener on `nembot_payment_status_update` which will be triggered when a
        // Transaction with MESSAGE being the invoiceNumber OR SENDER PUBLIC KEY being the payerXEM, is received
        // (/unconfirmed &  /transactions). When the transaction is included in a block, another event will be
        // will be triggered (`nembot_payment_status_update` again) with status `completed`, this time.
        // Only the second call with completed status should be trusted as a paid amount for the invoice.

        var socket = require("socket.io-client");
        var channelSocket = socket.connect(NEMBot_for_pacNEM.paymentBot.host);
        var channelParams = {
            message: invoice.number,
            sender: invoice.payerXEM,
            recipient: invoice.recipientXEM,
            amount: invoice.amount,
            maxDuration: 5 * 60 * 1000
        };

        self.logger_.info(__smartfilename, __line, '[BOT] open_channel(' + JSON.stringify(channelParams) + ') with NEMBot host: ' + NEMBot_for_pacNEM.paymentBot.host);
        channelSocket.emit("nembot_open_payment_channel", JSON.stringify(channelParams));

        // configure payment status update event FORWARDING (comes from NEMBot and forwards to Frontend)
        channelSocket.on("nembot_payment_status_update", function(rawdata)
            {
                self.logger_.info(__smartfilename, __line, '[' + channelSocket.id + '] [BOT] nembot_payment_status_update(' + rawdata + ')');

                var data = JSON.parse(rawdata);

                // forward to client..
                var clientData = {
                    status: data.status,
                    paymentData: data
                };
                io.sockets.to(clientSocketId)
                  .emit("pacnem_payment_status_update", JSON.stringify(clientData));

                // do the UI magic
                self.storeInvoiceStatusUpdate(data);
            });

        // save new backend socket ID to invoice.
        if (! invoice.socketIds || ! invoice.socketIds.length)
            invoice.socketIds = [channelSocket.id];
        else {
            var sockets = invoice.socketIds;
            sockets.push(channelSocket.id);

            invoice.socketIds = sockets;
        }

        if (! botChannelSockets_.hasOwnProperty(invoice.number))
            botChannelSockets_[invoice.number] = [];

        botChannelSockets_[invoice.number].push({socket: channelSocket, clientId: clientSocketId});

        invoice.save(function(err)
            {
                callback(invoice);
            });
    };

    /**
     * This function saves an invoice status update to the
     * database. It helps keeping track of the payment states.
     *
     * When the data is saved to the database, a custom callback
     * will be executed to send a transaction using our pacNEM
     * Multi Signature Account so that the the buyer receives
     * the bought evias.pacnem:heart Mosaics.
     *
     * @param  {object} data
     * @return {void}
     */
    this.storeInvoiceStatusUpdate = function(data)
    {
        var self = this;
        var invoiceQuery = {};

        if (typeof data.message != 'undefined' && data.message.length) {
            // Player sent message along with transaction.
            invoiceQuery["number"] = data.message;
        }
        else if (typeof data.sender != 'undefined' && data.sender.length) {
            // Player didn't send a Message with the transaction..
            invoiceQuery["payerXEM"] = data.sender;
        }

        //DEBUG self.logger_.info("[PACNEM] [INVOICE]", "[DEBUG]", 'Fetching invoice with: ' + JSON.stringify(data));

        // find invoice and update status and amounts
        self.db_.NEMPaymentChannel.findOne(invoiceQuery, function(err, invoice)
        {
            if (! err && invoice) {
                invoice.status = data.status;

                if (data.status == "unconfirmed")
                    invoice.amountUnconfirmed = data.amountUnconfirmed;
                else if (data.amountPaid)
                    invoice.amountPaid = data.amountPaid;

                if (data.status == "paid") {
                    invoice.isPaid = true;
                    invoice.paidAt = new Date().valueOf();
                }

                invoice.save(function(err)
                {
                    if (err) {
                        self.logger_.error(__smartfilename, __line, '[ERROR] Invoice status update error: ' + err);
                        return false;
                    }

                    if (data.status == "paid" && invoice.isPaid === true) {
                        self.closePaymentChannel(invoice);
                    }
                });
            }
        });
    }

    this.closePaymentChannel = function(paymentChannel)
    {
        var self = this;
        self.blockchain_.sendHeartsForPayment(paymentChannel, function(paymentChannel)
        {
            // forward "DONE PAYMENT" to client..
            var clientData = {
                status: paymentChannel.status,
                number: paymentChannel.number
            };

            if (botChannelSockets_.hasOwnProperty(paymentChannel.number)) {
                //var clientSocketId = botChannelSockets_[paymentChannel.number].clientId;
                var socketsForPayment = botChannelSockets_[paymentChannel.number];

                for (var i in socketsForPayment)
                    self.socketIO_.sockets.to(socketsForPayment[i].clientId)
                        .emit("pacnem_payment_success", JSON.stringify(clientData));
            }
        });
    };

};

module.exports.PaymentsCore = PaymentsCore;
}());
<|endoftext|>


<commit_before>// functions to help determine which files are compatible with the chromecast
// uses ffprobe to read media files

//todo:
//test on large libraries for any timeout issues

// Chromecast Media Player officially supports:
// Video codecs: H.264 High Profile Level 4.1, 4.2 and 5, VP8
// Audio decoding: HE-AAC, LC-AAC, CELT/Opus, MP3, Vorbis
// Image formats: BMP, GIF, JPEG, PNG, WEBP
// Containers: MP4, WebM
//
// Unofficial support:
// Video: h264 level 3.1
// Containers: MKV (presented as mp4)

var probe = require('node-ffprobe');
var path = require('path');
var fs = require('fs');

//cache the responses from reading ff-probe
//based on the mtime of the file
var probe_cache = {}

//function to cache the results of probe
var probe_check_cache = function(file, callback){
	var stats = fs.statSync(file);

	var append_probe_cache = function(err, probeData){
				if(probeData){
					probe_cache[file] = {}
					probe_cache[file].stats = stats;
					probe_cache[file].probeData = probeData;
				}
				callback(err, probeData)
			}

	if(file in probe_cache){
		if(probe_cache[file].stats.mtime.valueOf() != stats.mtime.valueOf()){
			probe(file, append_probe_cache);
		} else {
			callback(0, probe_cache[file].probeData)
		}
	} else {
		probe(file, append_probe_cache);
	}
}

var is_compatibile = function(file, callback){
	//callback is: function(compatibility, data)
	//where data gives specifics about what is and isn't compatible
	//includes the output from ffprobe under ffprobe_data

	probe_check_cache(file, function(err, probeData) {
		var obj = {
			audio: 0,
			video: 0,
			container: 0,
			ffprobe_data: undefined
		}

		if(probeData == undefined){
			callback(0, obj);
			return
		}
		obj.ffprobe_data = probeData;

		/*console.log("--")
		console.log(probeData)
		console.log("--")*/
		for(i in probeData.streams){
			stream = probeData.streams[i]
			if(stream.codec_type == 'video'
				&& stream.codec_name == 'h264'
				&& stream.profile == 'High'
				&& (stream.level == 31 || stream.level == 41 || stream.level == 42 || stream.level == 5)
				){
					obj.video = 1;
			}

			if(stream.codec_type == 'audio'
				&& (stream.codec_name == 'aac' || stream.codec_name == 'mp3' || stream.codec_name == 'vorbis' || stream.codec_name == 'opus')
				){
				obj.audio = 1
			}
		}

		//ffprobe returns a list of formats that the container might be classified as
		// i.e. for mp4/mov/etc we'll get a string that looks like: 'mov,mp4,m4a,3gp,3g2,mj2'
		if(  probeData.format.format_name.split(",").indexOf("mp4") > -1 ){
			obj.container = 1;
		}

		compat = 0
		if(obj.audio == 1 && obj.video==1 && obj.container == 1){
			compat = 1;
		}
		callback(compat, obj)
	});
}

var read_dir = function(basedir, dir, callback){
	//calls callback with an array of files
	//containing the stats of the file as well as the chromecast compatibility
	var response_obj = {}
	var to_check = [];

	real_dir = path.join(basedir, dir)
	files = fs.readdirSync(real_dir);
	files.forEach(function(f){
		var file = path.join(dir, f);
		var file_loc = path.join(basedir, file);

		//fill in information about the file in this dir
		stats = fs.statSync(file_loc);
		response_obj[file] = {
				compatibility_data: undefined,
				compatible: 0,
				is_dir: 0,
				stats: stats
			};

		if(stats && stats.isFile()){
			to_check.push(file);
		} else if ( stats && stats.isDirectory()){
			response_obj[file].is_dir = 1;
		}
	});

	var append_compat = function(file){
			console.log("checking compatbility: basedir: "+basedir+" file: "+file)
			is_compatibile(path.join(basedir, file), function(compat, data){
				response_obj[file].compatibility_data = data;
				response_obj[file].compatible = compat;

				if(to_check.length > 0){
					append_compat(to_check.pop());
				} else {
					callback(response_obj);
				}
			});
		};

	if(to_check.length > 0){
		append_compat(to_check.pop());
	} else {
		callback(response_obj);
	}
}

/*var transcode_recommendation = function(file, callback){
	//calls callback with (suggested_ffmpeg_command, data)
	//where suggested_ffmpeg_command is the suggested command to do the conversion to a CC supported format
	//it's smart enough to not transcode streams that already work
	//where data contains the response from is_compatible

	is_compatible(file, function(compat, ffprobe_data){
		command = "do nothing"
		if(compat == 0){
			command = "ffmpeg " + file
		}
		callback(command, ffprobe_data)
	})
}*/

module.exports = {
  is_compatibile: is_compatibile,
  read_dir: read_dir,
  //transcode_recommendation: transcode_recommendation
}<commit_msg>compatibility updated with webm<commit_after>// functions to help determine which files are compatible with the chromecast
// uses ffprobe to read media files

//todo:
//test on large libraries for any timeout issues

// Chromecast Media Player officially supports:
// Video codecs: H.264 High Profile Level 4.1, 4.2 and 5, VP8
// Audio decoding: HE-AAC, LC-AAC, CELT/Opus, MP3, Vorbis
// Image formats: BMP, GIF, JPEG, PNG, WEBP
// Containers: MP4, WebM
//
// Unofficial support:
// Video: h264 level 3.1
// Containers: MKV (presented as mp4)

var probe = require('node-ffprobe');
var path = require('path');
var fs = require('fs');

//cache the responses from reading ff-probe
//based on the mtime of the file
var probe_cache = {}

//function to cache the results of probe
var probe_check_cache = function(file, callback){
	var stats = fs.statSync(file);

	var append_probe_cache = function(err, probeData){
				if(probeData){
					probe_cache[file] = {}
					probe_cache[file].stats = stats;
					probe_cache[file].probeData = probeData;
				}
				callback(err, probeData)
			}

	if(file in probe_cache){
		if(probe_cache[file].stats.mtime.valueOf() != stats.mtime.valueOf()){
			probe(file, append_probe_cache);
		} else {
			callback(0, probe_cache[file].probeData)
		}
	} else {
		probe(file, append_probe_cache);
	}
}

var is_compatibile = function(file, callback){
	//callback is: function(compatibility, data)
	//where data gives specifics about what is and isn't compatible
	//includes the output from ffprobe under ffprobe_data

	probe_check_cache(file, function(err, probeData) {
		var obj = {
			audio: 0,
			video: 0,
			container: 0,
			ffprobe_data: undefined
		}

		if(probeData == undefined){
			callback(0, obj);
			return
		}
		obj.ffprobe_data = probeData;

		/*console.log("--")
		console.log(probeData)
		console.log("--")*/
		for(i in probeData.streams){
			stream = probeData.streams[i]
			if(stream.codec_type == 'video'
				&& stream.codec_name == 'h264'
				&& stream.profile == 'High'
				&& (stream.level == 31 || stream.level == 41 || stream.level == 42 || stream.level == 5)
				){
					obj.video = 1;
			}

			if(stream.codec_type == 'audio'
				&& (stream.codec_name == 'aac' || stream.codec_name == 'mp3' || stream.codec_name == 'vorbis' || stream.codec_name == 'opus')
				){
				obj.audio = 1
			}
		}

		//ffprobe returns a list of formats that the container might be classified as
		// i.e. for mp4/mov/etc we'll get a string that looks like: 'mov,mp4,m4a,3gp,3g2,mj2'
		if(  probeData.format.format_name.split(",").indexOf("mp4") > -1 || probeData.format.format_name.split(",").indexOf("webm") > -1){
			obj.container = 1;
		}

		compat = 0
		if(obj.audio == 1 && obj.video==1 && obj.container == 1){
			compat = 1;
		}
		callback(compat, obj)
	});
}

var read_dir = function(basedir, dir, callback){
	//calls callback with an array of files
	//containing the stats of the file as well as the chromecast compatibility
	var response_obj = {}
	var to_check = [];

	real_dir = path.join(basedir, dir)
	files = fs.readdirSync(real_dir);
	files.forEach(function(f){
		var file = path.join(dir, f);
		var file_loc = path.join(basedir, file);

		//fill in information about the file in this dir
		stats = fs.statSync(file_loc);
		response_obj[file] = {
				compatibility_data: undefined,
				compatible: 0,
				is_dir: 0,
				stats: stats
			};

		if(stats && stats.isFile()){
			to_check.push(file);
		} else if ( stats && stats.isDirectory()){
			response_obj[file].is_dir = 1;
		}
	});

	var append_compat = function(file){
			console.log("checking compatbility: basedir: "+basedir+" file: "+file)
			is_compatibile(path.join(basedir, file), function(compat, data){
				response_obj[file].compatibility_data = data;
				response_obj[file].compatible = compat;

				if(to_check.length > 0){
					append_compat(to_check.pop());
				} else {
					callback(response_obj);
				}
			});
		};

	if(to_check.length > 0){
		append_compat(to_check.pop());
	} else {
		callback(response_obj);
	}
}

/*var transcode_recommendation = function(file, callback){
	//calls callback with (suggested_ffmpeg_command, data)
	//where suggested_ffmpeg_command is the suggested command to do the conversion to a CC supported format
	//it's smart enough to not transcode streams that already work
	//where data contains the response from is_compatible

	is_compatible(file, function(compat, ffprobe_data){
		command = "do nothing"
		if(compat == 0){
			command = "ffmpeg " + file
		}
		callback(command, ffprobe_data)
	})
}*/

module.exports = {
  is_compatibile: is_compatibile,
  read_dir: read_dir,
  //transcode_recommendation: transcode_recommendation
}<|endoftext|>


<commit_before>eveui_mode = 'modal';
var eveui_imageserver = function(image_ref) {
	if (image_ref.startsWith('Character')) {
		return eve_image(encodeURI(image_ref), 'jpg');
	}
	return eve_image(encodeURI(image_ref), 'png');
};
// fix for getting names for modules from ccp api that are in the users browser language
eveui_accept_language = document.documentElement.getAttribute('lang');
if (eveui_accept_language.startsWith('en_') || eveui_accept_language == 'en') {
	eveui_accept_language = 'en_us';
}
<commit_msg>changed language code used to send to esi from en_us to en-us<commit_after>eveui_mode = 'modal';
var eveui_imageserver = function(image_ref) {
	if (image_ref.startsWith('Character')) {
		return eve_image(encodeURI(image_ref), 'jpg');
	}
	return eve_image(encodeURI(image_ref), 'png');
};
// fix for getting names for modules from ccp api that are in the users browser language
eveui_accept_language = document.documentElement.getAttribute('lang');
if (eveui_accept_language.startsWith('en_') || eveui_accept_language == 'en') {
	eveui_accept_language = 'en-us';
}
<|endoftext|>


<commit_before>/*************************
 * TRAVIS DEV BUILD STEPS
 *************************/
const { exec, execSync } = require('child_process');
const util               = require('util');
const execPromise        = util.promisify(exec);

/* Steps
 ********/
const Steps = (paths, components) => { // :{}
	return {
		cloneComponentRepos() {
			const cloneCmd = 'git clone --depth 1';
			const opts     = { cwd: paths.components, stdio: [0,1,2] };
			let promises   = [];
			for (const [i, repoName] of components.repoNames.entries()) {
				console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
				let cmd = `${cloneCmd} ${repoName}`;
				// const promise = () => { return execPromise(cmd, opts); }
				// execSync(cmd, opts); console.log();
				// promises.push(promise);
				promises.push(execPromise(cmd, opts).then((x, y, z) => {
					console.log(x);
					console.log(y);
					console.log(x);
				});
			}
			return Promise.all(promises);
		},

		setupComponents() {
			const cmd  = 'rapid-build prod publish && npm run link'
			const opts = { stdio: [0,1,2] };
			for (const name of components.names) {
				console.info(`setup component ${name}`.toUpperCase().alert);
				opts.cwd = `${paths.components}/${name}`
				execSync(cmd, opts); console.log();
			}
		},

		setupShowcase() {
			const cmd  = 'npm run setup'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`setup showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		},

		buildShowcase() {
			const cmd  = 'rapid-build prod publish'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`build showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		}
	};
};

/* Export It!
 *************/
module.exports = Steps;
<commit_msg>chore(travis): try to clone components asynchronously<commit_after>/*************************
 * TRAVIS DEV BUILD STEPS
 *************************/
const { exec, execSync } = require('child_process');
const util               = require('util');
const execPromise        = util.promisify(exec);

/* Steps
 ********/
const Steps = (paths, components) => { // :{}
	return {
		cloneComponentRepos() {
			const cloneCmd = 'git clone --depth 1';
			const opts     = { cwd: paths.components, stdio: [0,1,2] };
			let promises   = [];
			for (const [i, repoName] of components.repoNames.entries()) {
				console.info(`cloning ${components.names[i]}`.toUpperCase().alert);
				let cmd = `${cloneCmd} ${repoName}`;
				// const promise = () => { return execPromise(cmd, opts); }
				// execSync(cmd, opts); console.log();
				// promises.push(promise);
				promises.push(
					execPromise(cmd, opts).then((x, y, z) => {
						console.log(x);
						console.log(y);
						console.log(x);
					})
				);
			}
			return Promise.all(promises);
		},

		setupComponents() {
			const cmd  = 'rapid-build prod publish && npm run link'
			const opts = { stdio: [0,1,2] };
			for (const name of components.names) {
				console.info(`setup component ${name}`.toUpperCase().alert);
				opts.cwd = `${paths.components}/${name}`
				execSync(cmd, opts); console.log();
			}
		},

		setupShowcase() {
			const cmd  = 'npm run setup'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`setup showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		},

		buildShowcase() {
			const cmd  = 'rapid-build prod publish'
			const opts = { cwd: paths.showcase, stdio: [0,1,2] };
			console.info(`build showcase`.toUpperCase().alert);
			execSync(cmd, opts); console.log();
		}
	};
};

/* Export It!
 *************/
module.exports = Steps;
<|endoftext|>


<commit_before>/**
 * @author Takahiro / https://github.com/takahirox
 */

// VRM Specification: https://dwango.github.io/vrm/vrm_spec/
//
// VRM is based on glTF 2.0 and VRM extension is defined
// in top-level json.extensions.VRM

THREE.VRMLoader = ( function () {

	function VRMLoader( manager ) {

		if ( THREE.GLTFLoader === undefined ) {

			throw new Error( 'THREE.VRMLoader: Import THREE.GLTFLoader.' );

		}

		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
		this.gltfLoader = new THREE.GLTFLoader( this.manager );

	}

	VRMLoader.prototype = {

		constructor: VRMLoader,

		crossOrigin: 'Anonymous',

		load: function ( url, onLoad, onProgress, onError ) {

			this.gltfLoader.load( url, onLoad, onProgress, onError );

		},

		setCrossOrigin: function ( value ) {

			this.glTFLoader.setCrossOrigin( value );
			return this;

		},

		setPath: function ( value ) {

			this.glTFLoader.setPath( value );
			return this;

		},

		setDRACOLoader: function ( dracoLoader ) {

			this.glTFLoader.setDRACOLoader( dracoLoader );
			return this;

		}

	};

	return VRMLoader;

} )();
<commit_msg>VRMLoader prototype update<commit_after>/**
 * @author Takahiro / https://github.com/takahirox
 */

// VRM Specification: https://dwango.github.io/vrm/vrm_spec/
//
// VRM is based on glTF 2.0 and VRM extension is defined
// in top-level json.extensions.VRM

THREE.VRMLoader = ( function () {

	function VRMLoader( manager ) {

		if ( THREE.GLTFLoader === undefined ) {

			throw new Error( 'THREE.VRMLoader: Import THREE.GLTFLoader.' );

		}

		this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
		this.gltfLoader = new THREE.GLTFLoader( this.manager );

	}

	VRMLoader.prototype = {

		constructor: VRMLoader,

		crossOrigin: 'Anonymous',

		load: function ( url, onLoad, onProgress, onError ) {

			var scope = this;

			this.gltfLoader.load( url, function ( gltf ) {

				scope.parse( gltf, onLoad );

			}, onProgress, onError );

		},

		setCrossOrigin: function ( value ) {

			this.glTFLoader.setCrossOrigin( value );
			return this;

		},

		setPath: function ( value ) {

			this.glTFLoader.setPath( value );
			return this;

		},

		setDRACOLoader: function ( dracoLoader ) {

			this.glTFLoader.setDRACOLoader( dracoLoader );
			return this;

		},

		parse: function ( gltf, onLoad ) {

			var gltfParser = gltf.parser;
			var gltfExtensions = gltf.userData.gltfExtensions || {};
			var vrmExtension = gltfExtensions.VRM || {};

			// handle VRM Extension here

			onLoad( gltf );

		}

	};

	return VRMLoader;

} )();
<|endoftext|>


<commit_before>//
// This file made available under CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/legalcode)
//
// Ensure CloudTrail is Enabled for All Regions
// Description: Checks that a CloudTrail exists that is set to multi-region
//
// Trigger Type: Periodic
// Required Parameter: None

var aws = require('aws-sdk');
var s3 = new aws.S3();
var zlib = require('zlib');
var config = new aws.ConfigService();

// This function checks whether CloudTrail is enabled with multi region trail in the home region.
// Do not use this rule in other regions.

function evaluateCompliance(configurationItems, ruleParameters, context) {
    checkDefined(configurationItems, "configurationItems");
    checkDefined(ruleParameters, "ruleParameters");

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

        var item = configurationItems[i];

        if (item.resourceType === 'AWS::CloudTrail::Trail') {

            if (item.configuration.isMultiRegionTrail) { return 'COMPLIANT'; }

        }

    }

    return 'NON_COMPLIANT';

}

// Helper function used to validate input

function checkDefined(reference, referenceName) {
    if (!reference) {
        console.log("Error: " + referenceName + " is not defined");
        throw referenceName;
    }
    return reference;
}

// Extract the account ID from the event

function getAccountId(invokingEvent) {
    checkDefined(invokingEvent, "invokingEvent");
    checkDefined(invokingEvent.s3ObjectKey, "invokingEvent.s3ObjectKey");
    var accountIdPattern = /AWSLogs\/(\d+)\/Config/;
    return accountIdPattern.exec(invokingEvent.s3ObjectKey)[1];
}

// readSnapshot Constructor for retrieving config s3 bucket region
var readSnapshot = function(s3key, s3bucket, callback) {

    s3.getBucketLocation({"Bucket": s3bucket}, function (err,data){
        if(err){
            callback(err,data);
        } else {
            var s3region = data.LocationConstraint ? data.LocationConstraint : 'us-east-1';
            readSnapshot.returnConfig(s3key, s3bucket, s3region, callback);
        }
    });
};

// Reads and parses the ConfigurationSnapshot from the S3 bucket
// where Config is set up to deliver
readSnapshot.returnConfig = function(s3key, s3bucket, s3region, callback){

    var s3client = new aws.S3({region: s3region});

    var params = {
        Key: s3key,
        Bucket: s3bucket
    };
    var buffer = "";
    s3client.getObject(params)
        .createReadStream()
        .pipe(zlib.createGunzip())
        .on('data', function(chunk) {
            buffer = buffer + chunk;
        })
        .on('end', function() {
            callback(null, JSON.parse(buffer));
        })
        .on('error', function(err) {
            callback(err, null);
        });

};

// This is the handler that's invoked by Lambda
// Most of this code is boilerplate; use as is

exports.handler = function(event, context) {
    checkDefined(event, "event");
    var invokingEvent = JSON.parse(event.invokingEvent);
    var ruleParameters = JSON.parse(event.ruleParameters);
    var s3key = invokingEvent.s3ObjectKey;
    var s3bucket = invokingEvent.s3Bucket;
    var accountId = getAccountId(invokingEvent);
    var orderingTimestamp = invokingEvent.notificationCreationTime;

    readSnapshot(s3key, s3bucket, function(err, snapshot) {
        var evaluation, putEvaluationsRequest;
        if (err === null) {
            evaluation = {
                ComplianceResourceType: 'AWS::::Account',
                ComplianceResourceId: accountId,
                ComplianceType: evaluateCompliance(snapshot.configurationItems, ruleParameters, context),
                OrderingTimestamp: orderingTimestamp
            };
            putEvaluationsRequest = {
               Evaluations: [
                   evaluation
               ],
               ResultToken: event.resultToken
            };
            config.putEvaluations(putEvaluationsRequest, function (err, data) {
                if (err) {
                    context.fail(err);
                } else {
                    context.succeed(data);
                }
            });
        } else {
            context.fail(err);
        }
    });
};
<commit_msg>Reverted to simpler callback<commit_after>//
// This file made available under CC0 1.0 Universal (https://creativecommons.org/publicdomain/zero/1.0/legalcode)
//
// Ensure CloudTrail is Enabled for All Regions
// Description: Checks that a CloudTrail exists that is set to multi-region
//
// Trigger Type: Periodic
// Required Parameter: None

var aws = require('aws-sdk');
var s3 = new aws.S3();
var zlib = require('zlib');
var config = new aws.ConfigService();

// This function checks whether CloudTrail is enabled with multi region trail in the home region.
// Do not use this rule in other regions.

function evaluateCompliance(configurationItems, ruleParameters, context) {
    checkDefined(configurationItems, "configurationItems");
    checkDefined(ruleParameters, "ruleParameters");

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

        var item = configurationItems[i];

        if (item.resourceType === 'AWS::CloudTrail::Trail') {

            if (item.configuration.isMultiRegionTrail) { return 'COMPLIANT'; }

        }

    }

    return 'NON_COMPLIANT';

}

// Helper function used to validate input

function checkDefined(reference, referenceName) {
    if (!reference) {
        console.log("Error: " + referenceName + " is not defined");
        throw referenceName;
    }
    return reference;
}

// Extract the account ID from the event

function getAccountId(invokingEvent) {
    checkDefined(invokingEvent, "invokingEvent");
    checkDefined(invokingEvent.s3ObjectKey, "invokingEvent.s3ObjectKey");
    var accountIdPattern = /AWSLogs\/(\d+)\/Config/;
    return accountIdPattern.exec(invokingEvent.s3ObjectKey)[1];
}

// Reads and parses the ConfigurationSnapshot from the S3 bucket
// where Config is set up to deliver

function readSnapshot(s3client, s3key, s3bucket, callback) {

    s3client.getBucketLocation({"Bucket": s3bucket}, function (err,data){
        if(err){
            callback(err,data);
        }

        // If no region is returned the bucket is "US Standard" (aka us-east-1)
        s3client = new aws.S3({region: data.LocationConstraint ? data.LocationConstraint : 'us-east-1'});
        var params = {
            Key: s3key,
            Bucket: s3bucket
        };
        var buffer = "";
        s3client.getObject(params)
            .createReadStream()
            .pipe(zlib.createGunzip())
            .on('data', function(chunk) {
                buffer = buffer + chunk;
            })
            .on('end', function() {
                callback(null, JSON.parse(buffer));
            })
            .on('error', function(err) {
                callback(err, null);
            });
    });
}

// This is the handler that's invoked by Lambda
// Most of this code is boilerplate; use as is

exports.handler = function(event, context) {
    checkDefined(event, "event");

    var invokingEvent = JSON.parse(event.invokingEvent);
    var ruleParameters = JSON.parse(event.ruleParameters);
    var s3key = invokingEvent.s3ObjectKey;
    var s3bucket = invokingEvent.s3Bucket;
    var accountId = getAccountId(invokingEvent);
    var orderingTimestamp = invokingEvent.notificationCreationTime;
    readSnapshot(s3, s3key, s3bucket, function(err, snapshot) {
        var evaluation, putEvaluationsRequest;
        if (err === null) {
            evaluation = {
                ComplianceResourceType: 'AWS::::Account',
                ComplianceResourceId: accountId,
                ComplianceType: evaluateCompliance(snapshot.configurationItems, ruleParameters, context),
                OrderingTimestamp: orderingTimestamp
            };
            putEvaluationsRequest = {
               Evaluations: [
                   evaluation
               ],
               ResultToken: event.resultToken
            };
            config.putEvaluations(putEvaluationsRequest, function (err, data) {
                if (err) {
                    context.fail(err);
                } else {
                    context.succeed(data);
                }
            });
        } else {
            context.fail(err);
        }
    });
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { OverlaySigil } from './overlay-sigil';
import MessageContent from './message-content';
import { uxToHex, cite, writeText } from '../../../../lib/util';
import moment from 'moment';

export class Message extends Component {
  constructor() {
    super();
    this.state = {
      copied: false
    };
  }

  render() {
    const { props, state } = this;

    const pending = props.msg.pending ? ' o-40' : '';
    const containerClass =
      props.renderSigil ?
        `w-100 f7 pl3 pt4 pr3 cf flex lh-copy ` + pending :
        'w-100 pr3 cf hide-child flex' + pending;

    const timestamp =
      moment.unix(props.msg.when / 1000).format(
        props.renderSigil ? 'hh:mm a' : 'hh:mm'
      );

    return (

        {
          props.renderSigil ? (
            this.renderWithSigil(timestamp)
          ) : (
            this.renderWithoutSigil(timestamp)
          )
        }

    );
  }

  renderWithSigil(timestamp) {
    const { props, state } = this;
    const paddingTop = props.paddingTop ? { 'paddingTop': '6px' } : '';
    const datestamp =
      '~' + moment.unix(props.msg.when / 1000).format('YYYY.M.D');

    const contact = props.msg.author in props.contacts
      ? props.contacts[props.msg.author] : false;
    let name = `~${props.msg.author}`;
    let color = '#000000';
    let sigilClass = 'mix-blend-diff';
    if (contact) {
      name = (contact.nickname.length > 0)
        ? contact.nickname : `~${props.msg.author}`;
      color = `#${uxToHex(contact.color)}`;
      sigilClass = '';
    }

    if (`~${props.msg.author}` === name) {
      name = cite(props.msg.author);
    }

    return (

        <OverlaySigil
          ship={props.msg.author}
          contact={contact}
          color={color}
          sigilClass={sigilClass}
          association={props.association}
          group={props.group}
          className="fl pr3 v-top bg-white bg-gray0-d"
        />

            <p className={`v-mid f9 gray2 dib mr3 c-default`}>
               {
                  writeText(props.msg.author);
                  this.setState({ copied: true });
                  setTimeout(() => {
                    this.setState({ copied: false });
                  }, 800);
                }}
                title={`~${props.msg.author}`}
              >
                {state.copied && 'Copied' || name}

            <p className={`v-mid mono f9 gray2 dib`}>{timestamp}

            <p className={`v-mid mono f9 ml2 gray2 dib child dn-s`}>
              {datestamp}

          <MessageContent letter={props.msg.letter} />

    );
  }

  renderWithoutSigil(timestamp) {
    const { props } = this;

    return (

{timestamp}

        <MessageContent letter={props.msg.letter} />

    );
  }
}
<commit_msg>chat: truncate long nicknames<commit_after>import React, { Component } from 'react';
import { OverlaySigil } from './overlay-sigil';
import MessageContent from './message-content';
import { uxToHex, cite, writeText } from '../../../../lib/util';
import moment from 'moment';

export class Message extends Component {
  constructor() {
    super();
    this.state = {
      copied: false
    };
  }

  render() {
    const { props, state } = this;

    const pending = props.msg.pending ? ' o-40' : '';
    const containerClass =
      props.renderSigil ?
        `w-100 f7 pl3 pt4 pr3 cf flex lh-copy ` + pending :
        'w-100 pr3 cf hide-child flex' + pending;

    const timestamp =
      moment.unix(props.msg.when / 1000).format(
        props.renderSigil ? 'hh:mm a' : 'hh:mm'
      );

    return (

        {
          props.renderSigil ? (
            this.renderWithSigil(timestamp)
          ) : (
            this.renderWithoutSigil(timestamp)
          )
        }

    );
  }

  renderWithSigil(timestamp) {
    const { props, state } = this;
    const paddingTop = props.paddingTop ? { 'paddingTop': '6px' } : '';
    const datestamp =
      '~' + moment.unix(props.msg.when / 1000).format('YYYY.M.D');

    const contact = props.msg.author in props.contacts
      ? props.contacts[props.msg.author] : false;
    let name = `~${props.msg.author}`;
    let color = '#000000';
    let sigilClass = 'mix-blend-diff';
    if (contact) {
      name = (contact.nickname.length > 0)
        ? contact.nickname : `~${props.msg.author}`;
      color = `#${uxToHex(contact.color)}`;
      sigilClass = '';
    }

    if (`~${props.msg.author}` === name) {
      name = cite(props.msg.author);
    }

    return (

        <OverlaySigil
          ship={props.msg.author}
          contact={contact}
          color={color}
          sigilClass={sigilClass}
          association={props.association}
          group={props.group}
          className="fl pr3 v-top bg-white bg-gray0-d"
        />

            <p className={`v-mid f9 gray2 dib mr3 c-default`}>
               {
                  writeText(props.msg.author);
                  this.setState({ copied: true });
                  setTimeout(() => {
                    this.setState({ copied: false });
                  }, 800);
                }}
                title={`~${props.msg.author}`}
              >
                {state.copied && 'Copied' || name}

            <p className={`v-mid mono f9 gray2 dib`}>{timestamp}

            <p className={`v-mid mono f9 ml2 gray2 dib child dn-s`}>
              {datestamp}

          <MessageContent letter={props.msg.letter} />

    );
  }

  renderWithoutSigil(timestamp) {
    const { props } = this;

    return (

{timestamp}

        <MessageContent letter={props.msg.letter} />

    );
  }
}
<|endoftext|>


<commit_before>/*
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';

export default class MessageComposerFormatBar extends React.PureComponent {
    static propTypes = {
        onAction: PropTypes.func.isRequired,
        shortcuts: PropTypes.object.isRequired,
    }

    render() {
        return (
 this._formatBarRef = ref}>
            <FormatButton shortcut={this.props.shortcuts.bold} label={_t("Bold")} onClick={() => this.props.onAction("bold")} icon="Bold" />
            <FormatButton shortcut={this.props.shortcuts.italics} label={_t("Italics")} onClick={() => this.props.onAction("italics")} icon="Italic" />
            <FormatButton label={_t("Strikethrough")} onClick={() => this.props.onAction("strikethrough")} icon="Strikethrough" />
            <FormatButton label={_t("Code block")} onClick={() => this.props.onAction("code")} icon="Code" />
            <FormatButton shortcut={this.props.shortcuts.quote} label={_t("Quote")} onClick={() => this.props.onAction("quote")} icon="Quote" />

);
    }

    showAt(selectionRect) {
        this._formatBarRef.classList.add("mx_MessageComposerFormatBar_shown");
        let leftOffset = 0;
        let node = this._formatBarRef;
        while (node.offsetParent) {
            node = node.offsetParent;
            leftOffset += node.offsetLeft;
        }

        let topOffset = 0;
        node = this._formatBarRef;
        while (node.offsetParent) {
            node = node.offsetParent;
            topOffset += node.offsetTop;
        }

        this._formatBarRef.style.left = `${selectionRect.left - leftOffset}px`;
        // 12 is half the height of the bar (e.g. to center it) and 16 is an offset that felt ok.
        this._formatBarRef.style.top = `${selectionRect.top - topOffset - 16 - 12}px`;
    }

    hide() {
        this._formatBarRef.classList.remove("mx_MessageComposerFormatBar_shown");
    }
}

class FormatButton extends React.PureComponent {
    static propTypes = {
        label: PropTypes.string.isRequired,
        onClick: PropTypes.func.isRequired,
        icon: PropTypes.string.isRequired,
        shortcut: PropTypes.string,
    }

    render() {
        const InteractiveTooltip = sdk.getComponent('elements.InteractiveTooltip');
        const className = `mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIcon${this.props.icon}`;
        let shortcut;
        if (this.props.shortcut) {
            shortcut =
{this.props.shortcut}
;
        }
        const tooltipContent = (

{this.props.label}

                {shortcut}

        );

        return (
            <InteractiveTooltip content={tooltipContent}>

            </InteractiveTooltip>
        );
    }
}
<commit_msg>take bounding box for positioning calculation<commit_after>/*
Copyright 2019 The Matrix.org Foundation C.I.C.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

import React from 'react';
import PropTypes from 'prop-types';
import { _t } from '../../../languageHandler';
import sdk from '../../../index';

export default class MessageComposerFormatBar extends React.PureComponent {
    static propTypes = {
        onAction: PropTypes.func.isRequired,
        shortcuts: PropTypes.object.isRequired,
    }

    render() {
        return (
 this._formatBarRef = ref}>
            <FormatButton shortcut={this.props.shortcuts.bold} label={_t("Bold")} onClick={() => this.props.onAction("bold")} icon="Bold" />
            <FormatButton shortcut={this.props.shortcuts.italics} label={_t("Italics")} onClick={() => this.props.onAction("italics")} icon="Italic" />
            <FormatButton label={_t("Strikethrough")} onClick={() => this.props.onAction("strikethrough")} icon="Strikethrough" />
            <FormatButton label={_t("Code block")} onClick={() => this.props.onAction("code")} icon="Code" />
            <FormatButton shortcut={this.props.shortcuts.quote} label={_t("Quote")} onClick={() => this.props.onAction("quote")} icon="Quote" />

);
    }

    showAt(selectionRect) {
        this._formatBarRef.classList.add("mx_MessageComposerFormatBar_shown");
        const parentRect = this._formatBarRef.parentElement.getBoundingClientRect();
        this._formatBarRef.style.left = `${selectionRect.left - parentRect.left}px`;
        // 12 is half the height of the bar (e.g. to center it) and 16 is an offset that felt ok.
        this._formatBarRef.style.top = `${selectionRect.top - parentRect.top - 16 - 12}px`;
    }

    hide() {
        this._formatBarRef.classList.remove("mx_MessageComposerFormatBar_shown");
    }
}

class FormatButton extends React.PureComponent {
    static propTypes = {
        label: PropTypes.string.isRequired,
        onClick: PropTypes.func.isRequired,
        icon: PropTypes.string.isRequired,
        shortcut: PropTypes.string,
    }

    render() {
        const InteractiveTooltip = sdk.getComponent('elements.InteractiveTooltip');
        const className = `mx_MessageComposerFormatBar_button mx_MessageComposerFormatBar_buttonIcon${this.props.icon}`;
        let shortcut;
        if (this.props.shortcut) {
            shortcut =
{this.props.shortcut}
;
        }
        const tooltipContent = (

{this.props.label}

                {shortcut}

        );

        return (
            <InteractiveTooltip content={tooltipContent}>

            </InteractiveTooltip>
        );
    }
}
<|endoftext|>


<commit_before>var mongoose   = require('mongoose');
var config     = require('config');
var semver     = require('semver');
var util       = require('util')

var connectionString = config.mongodb.connectionString
if (!connectionString) {
	if(config.mongodb.user && config.mongodb.password) {
		connectionString = util.format('mongodb://%s:%s@%s/%s', config.mongodb.user, config.mongodb.password, config.mongodb.server, config.mongodb.database)
	} else {
		connectionString = util.format('mongodb://%s/%s', config.mongodb.server, config.mongodb.database)
	}
}

mongoose.connect(connectionString)
mongoose.connection.on('error', function (err) {
  console.error('MongoDB error: ' + err.message);
  console.error('Make sure a mongoDB server is running and accessible by this application');
  process.exit(1);
});

mongoose.connection.on('open', function (err) {
  mongoose.connection.db.admin().serverStatus(function(err, data) {
    if (err) {
      if (err.name === "MongoError" && (err.errmsg === 'need to login' || err.errmsg === 'unauthorized') && !config.mongodb.connectionString) {
        console.log('Forcing MongoDB authentication');
        mongoose.connection.db.authenticate(config.mongodb.user, config.mongodb.password, function(err) {
          if (!err) return;
          console.error(err);
          process.exit(1);
        });
        return;
      } else {
        console.error(err);
        process.exit(1);
      }
    }
    if (!semver.satisfies(data.version, '>=2.1.0')) {
      console.error('Error: Uptime requires MongoDB v2.1 minimum. The current MongoDB server uses only '+ data.version);
      process.exit(1);
    }
  });
});

module.exports = mongoose;
<commit_msg>Add check in bootstrap to detect if we are running trough fig. If so we change the connectionString to connect to the dockerized mongodb instance provided for us.<commit_after>var mongoose   = require('mongoose');
var config     = require('config');
var semver     = require('semver');
var util       = require('util')

var connectionString = config.mongodb.connectionString
if (!connectionString) {
	if(config.mongodb.user && config.mongodb.password) {
		connectionString = util.format('mongodb://%s:%s@%s/%s', config.mongodb.user, config.mongodb.password, config.mongodb.server, config.mongodb.database)
	} else {
		connectionString = util.format('mongodb://%s/%s', config.mongodb.server, config.mongodb.database)
	}
}

if (process.env.UPTIME_MONGO_1_PORT_27017_TCP_ADDR) {
	/* If this environment variable is set we are running trough fig.
	   This is the worst hack I have ever done. I feel ashamed.
	*/
	connectionString = util.format('mongodb://%s/%s', process.env.UPTIME_MONGO_1_PORT_27017_TCP_ADDR, config.mongodb.database)
}

mongoose.connect(connectionString)
mongoose.connection.on('error', function (err) {
  console.error('MongoDB error: ' + err.message);
  console.error('Make sure a mongoDB server is running and accessible by this application');
  process.exit(1);
});

mongoose.connection.on('open', function (err) {
  mongoose.connection.db.admin().serverStatus(function(err, data) {
    if (err) {
      if (err.name === "MongoError" && (err.errmsg === 'need to login' || err.errmsg === 'unauthorized') && !config.mongodb.connectionString) {
        console.log('Forcing MongoDB authentication');
        mongoose.connection.db.authenticate(config.mongodb.user, config.mongodb.password, function(err) {
          if (!err) return;
          console.error(err);
          process.exit(1);
        });
        return;
      } else {
        console.error(err);
        process.exit(1);
      }
    }
    if (!semver.satisfies(data.version, '>=2.1.0')) {
      console.error('Error: Uptime requires MongoDB v2.1 minimum. The current MongoDB server uses only '+ data.version);
      process.exit(1);
    }
  });
});

module.exports = mongoose;
<|endoftext|>


<commit_before>var helpers = require('../helpers');
var stringify = require('csv').stringify;
var fs = require('fs');
var path = require('path');
var util = require('./util');

module.exports = {};

module.exports.saveChangeset = saveChangeset;
module.exports.writeToCSV = writeToCSV;
module.exports.writeUsers = writeUsers;

var changesets = [];
var comments = [];
var tags = [];
var users = {};

var changesetsFile = path.join('csv', 'changesets.csv');
var commentsFile = path.join('csv', 'comments.csv');

function saveChangeset(changeset, next) {
    var attribs = changeset.attributes;
    if (attribs.OPEN === 'true' || attribs.COMMENTS_COUNT === '0') {
        return next();
    }
    var tags = util.getChangesetTags(changeset.tags);
    var row = [
        attribs.ID,
        attribs.CREATED_AT,
        attribs.CLOSED_AT ? attribs.CLOSED_AT : null,
        attribs.OPEN,
        attribs.UID,
        attribs.USER,
        tags.comment,
        tags.source,
        tags.created_by,
        tags.imagery_used,
        attribs.NUM_CHANGES,
        util.getIsUnreplied(attribs.UID, changeset.comments) ? 'true' : 'false',
        attribs.MIN_LON,
        attribs.MIN_LAT,
        attribs.MAX_LON,
        attribs.MAX_LAT
    ];
    changesets.push(row);
    addUser(attribs.UID, attribs.USER);
    changeset.comments.forEach(function(comment) {
        comment.changesetID = changeset.attributes.ID;
        var attribs = comment.attributes;
        var commentRow = [
            helpers.getHash(JSON.stringify(comment)),
            comment.changesetID,
            attribs.UID ? attribs.UID : null,
            attribs.DATE,
            comment.text
        ];
        comments.push(commentRow);
    });

    if (changesets.length > 10000) {
        writeToCSV(function() {
            next();
        });
    } else {
        next();
    }
}

function writeToCSV(callback) {
    console.log('writing CSV');
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(changesetsFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            writeTags(callback);
        });
    });
    changesets.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    changesets = [];
    return;
}

function writeComments(callback) {
    if (comments.length === 0) {
        callback();
        return;
    }
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(commentsFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            callback();
        });
    });
    comments.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    comments = [];
    return;
}

function writeUsers(callback) {
    var usersFile = path.join('csv', 'users.csv');
    var usersArray = [];
    for (var key in users) {
        var user = [
            key,
            users[key]
        ];
        usersArray.push(user);
    }
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(usersFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            callback();
        });;
    });
    usersArray.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    return;
}

function addUser(id, name) {
    if (!users.hasOwnProperty(id)) {
        users[id] = name;
    }
    return;
}<commit_msg>fix generating comments.csv during initial run<commit_after>var helpers = require('../helpers');
var stringify = require('csv').stringify;
var fs = require('fs');
var path = require('path');
var util = require('./util');

module.exports = {};

module.exports.saveChangeset = saveChangeset;
module.exports.writeToCSV = writeToCSV;
module.exports.writeUsers = writeUsers;

var changesets = [];
var comments = [];
var tags = [];
var users = {};

var changesetsFile = path.join('csv', 'changesets.csv');
var commentsFile = path.join('csv', 'comments.csv');

function saveChangeset(changeset, next) {
    var attribs = changeset.attributes;
    if (attribs.OPEN === 'true' || attribs.COMMENTS_COUNT === '0') {
        return next();
    }
    console.log("saving " + attribs.ID);
    var tags = util.getChangesetTags(changeset.tags);
    var row = [
        attribs.ID,
        attribs.CREATED_AT,
        attribs.CLOSED_AT ? attribs.CLOSED_AT : null,
        attribs.OPEN,
        attribs.UID,
        attribs.USER,
        tags.comment,
        tags.source,
        tags.created_by,
        tags.imagery_used,
        attribs.NUM_CHANGES,
        util.getIsUnreplied(attribs.UID, changeset.comments) ? 'true' : 'false',
        attribs.MIN_LON,
        attribs.MIN_LAT,
        attribs.MAX_LON,
        attribs.MAX_LAT
    ];
    changesets.push(row);
    addUser(attribs.UID, attribs.USER);
    changeset.comments.forEach(function(comment) {
        comment.changesetID = changeset.attributes.ID;
        var attribs = comment.attributes;
        var commentRow = [
            helpers.getHash(JSON.stringify(comment)),
            comment.changesetID,
            attribs.UID ? attribs.UID : null,
            attribs.DATE,
            comment.text
        ];
        comments.push(commentRow);
    });

    if (changesets.length > 10000) {
        writeToCSV(function() {
            next();
        });
    } else {
        next();
    }
}

function writeToCSV(callback) {
    console.log('writing CSV');
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(changesetsFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            writeComments(callback);
        });
    });
    changesets.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    changesets = [];
    return;
}

function writeComments(callback) {
    if (comments.length === 0) {
        callback();
        return;
    }
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(commentsFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            callback();
        });
    });
    comments.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    comments = [];
    return;
}

function writeUsers(callback) {
    var usersFile = path.join('csv', 'users.csv');
    var usersArray = [];
    for (var key in users) {
        var user = [
            key,
            users[key]
        ];
        usersArray.push(user);
    }
    var data = '';
    var stringifier = stringify();
    stringifier.on('readable', function(){
      while(row = stringifier.read()){
        data += row;
      }
    });
    stringifier.on('error', function(err){
      consol.log(err.message);
    });
    stringifier.on('finish', function(){
        var outStream = fs.createWriteStream(usersFile, {'flags': 'a'});
        outStream.write(data, function() {
            outStream.end();
            callback();
        });
    });
    usersArray.forEach(function(row) {
        stringifier.write(row);
    });
    stringifier.end();
    return;
}

function addUser(id, name) {
    if (!users.hasOwnProperty(id)) {
        users[id] = name;
    }
    return;
}<|endoftext|>


<commit_before>var uf      = require("../src/util_functions.js");
//Spaghetti code below VVVV
var kickData={}

module.exports=function(threadID, args, senderId){
	var api = uf.metaData.meta.api;
	var userKick = senderId;
	var userKickedId;
	var userKicked;
	if(kickData[threadID] == undefined){
		kickData[threadID] = {}
	}
	if(args.special.indexOf("--user") > -1){
		if(args.special_value.length==0){
			uf.sendMessage(threadID,"No user specified");
			return;
		}

		var threadUsers = uf.metaData.chatUsers[threadID];
		user_kicked = uf.getSpecialValue("--user",args);
		for(id in threadUsers){
			if(threadUsers[id].name.toLowerCase() == user_kicked.toLowerCase()){
				userKickedId = id;
				userKicked = threadUsers[id].name;

				if(kickData[threadID][userKickedId] == undefined){
					kickData[threadID][userKickedId] = {votes:[],name:""}
				}
				kickData[threadID][userKickedId].name = userKicked;

				if(kickData[threadID][userKickedId].votes.indexOf(senderId) == -1){

					kickData[threadID][userKickedId].votes.push(senderId);

					var voteSize = Object.keys(threadUsers).length;
					uf.sendMessage("Registered vote for "+userKicked+"\n"+kickData[threadID][userKickedId].votes.length+"/"+Math.round(voteSize/2),threadID);

					if(kickData[threadID][userKickedId].votes.length >= Math.round(voteSize/2)){

						api.removeUserFromGroup(userKickedId,threadID,function(err){
							if(err)console.log(err);
						});

					}
				}
				return
			}
		}
		uf.sendMessage("User not found",threadID);
	}
}
<commit_msg>Removed bot from group count<commit_after>var uf      = require("../src/util_functions.js");
//Spaghetti code below VVVV
var kickData={}

module.exports=function(threadID, args, senderId){
	var api = uf.metaData.meta.api;
	var userKick = senderId;
	var userKickedId;
	var userKicked;
	if(kickData[threadID] == undefined){
		kickData[threadID] = {}
	}
	if(args.special.indexOf("--user") > -1){
		if(args.special_value.length==0){
			uf.sendMessage(threadID,"No user specified");
			return;
		}

		var threadUsers = uf.metaData.chatUsers[threadID];
		user_kicked = uf.getSpecialValue("--user",args);
		for(id in threadUsers){
			if(threadUsers[id].name.toLowerCase() == user_kicked.toLowerCase()){
				userKickedId = id;
				userKicked = threadUsers[id].name;

				if(kickData[threadID][userKickedId] == undefined){
					kickData[threadID][userKickedId] = {votes:[],name:""}
				}
				kickData[threadID][userKickedId].name = userKicked;

				if(kickData[threadID][userKickedId].votes.indexOf(senderId) == -1){

					kickData[threadID][userKickedId].votes.push(senderId);

					var voteSize = Object.keys(threadUsers).length-1;
					uf.sendMessage("Registered vote for "+userKicked+"\n"+kickData[threadID][userKickedId].votes.length+"/"+Math.round(voteSize/2),threadID);

					if(kickData[threadID][userKickedId].votes.length >= Math.round(voteSize/2)){

						api.removeUserFromGroup(userKickedId,threadID,function(err){
							if(err)console.log(err);
						});

					}
				}
				return
			}
		}
		uf.sendMessage("User not found",threadID);
	}
}
<|endoftext|>