<commit_before>_kiwi.view.Channel = _kiwi.view.Panel.extend({
    events: function(){
        var parent_events = this.constructor.__super__.events;

        if(_.isFunction(parent_events)){
            parent_events = parent_events();
        }
        return _.extend({}, parent_events, {
            'click .msg .nick' : 'nickClick',
            "click .chan": "chanClick",
            'click .media .open': 'mediaClick',
            'mouseenter .msg .nick': 'msgEnter',
            'mouseleave .msg .nick': 'msgLeave'
        });
    },

    initialize: function (options) {
        this.initializePanel(options);

        // Container for all the messages
        this.$messages = $('

');
        this.$el.append(this.$messages);

        this.model.bind('change:topic', this.topic, this);

        if (this.model.get('members')) {
            this.model.get('members').bind('add', function (member) {
                if (member.get('nick') === this.model.collection.network.get('nick')) {
                    this.$el.find('.initial_loader').slideUp(function () {
                        $(this).remove();
                    });
                }
            }, this);
        }

        // Only show the loader if this is a channel (ie. not a query)
        if (this.model.isChannel()) {
            this.$el.append('
 ' + _kiwi.global.i18n.translate('client_views_channel_joining').fetch() + '
');
        }

        this.model.bind('msg', this.newMsg, this);
        this.msg_count = 0;
    },

    render: function () {
        var that = this;

        this.$messages.empty();
        _.each(this.model.get('scrollback'), function (msg) {
            that.newMsg(msg);
        });
    },

    newMsg: function (msg) {
        var re, line_msg,
            nick_colour_hex, nick_hex, is_highlight, msg_css_classes = '',
            time_difference,
            sb = this.model.get('scrollback'),
            prev_msg = sb[sb.length-2],
            network, hour, pm;

        // Nick highlight detecting
        if ((new RegExp('(^|\\W)(' + escapeRegex(_kiwi.app.connections.active_connection.get('nick')) + ')(\\W|$)', 'i')).test(msg.msg)) {
            is_highlight = true;
            msg_css_classes += ' highlight';
        }

        // Escape any HTML that may be in here
        msg.msg =  $('
').text(msg.msg).html();

        // Make the channels clickable
        if ((network = this.model.get('network'))) {
            re = new RegExp('(?:^|\\s)([' + escapeRegex(network.get('channel_prefix')) + '][^ ,\\007]+)', 'g');
            msg.msg = msg.msg.replace(re, function (match) {
                return '' + match + '';
            });
        }

        // Parse any links found
        msg.msg = msg.msg.replace(/(([A-Za-z][A-Za-z0-9\-]*\:\/\/)|(www\.))([\w.\-]+)([a-zA-Z]{2,6})(:[0-9]+)?(\/[\w#!:.?$'()[\]*,;~+=&%@!\-\/]*)?/gi, function (url) {
            var nice = url,
                extra_html = '';

            // Add the http if no protoocol was found
            if (url.match(/^www\./)) {
                url = 'http://' + url;
            }

            // Shorten the displayed URL if it's going to be too long
            if (nice.length > 100) {
                nice = nice.substr(0, 100) + '...';
            }

            // Get any media HTML if supported
            extra_html = _kiwi.view.MediaMessage.buildHtml(url);

            // Make the link clickable
            return '' + nice + '' + extra_html;
        });

        // Convert IRC formatting into HTML formatting
        msg.msg = formatIRCMsg(msg.msg);

        // Replace text emoticons with images
        if (_kiwi.global.settings.get('show_emoticons')) {
            msg.msg = emoticonFromText(msg.msg);
        }

        // Add some colours to the nick (Method based on IRSSIs nickcolor.pl)
        nick_colour_hex = (function (nick) {
            var nick_int = 0, rgb;

            _.map(nick.split(''), function (i) { nick_int += i.charCodeAt(0); });
            rgb = hsl2rgb(nick_int % 255, 70, 35);
            rgb = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16);

            return '#' + rgb.toString(16);
        })(msg.nick);

        msg.nick_style = 'color:' + nick_colour_hex + ';';

        // Generate a hex string from the nick to be used as a CSS class name
        nick_hex = msg.nick_css_class = '';
        if (msg.nick) {
            _.map(msg.nick.split(''), function (char) {
                nick_hex += char.charCodeAt(0).toString(16);
            });
            msg_css_classes += ' nick_' + nick_hex;
        }

        if (prev_msg) {
            // Time difference between this message and the last (in minutes)
            time_difference = (msg.time.getTime() - prev_msg.time.getTime())/1000/60;
            if (prev_msg.nick === msg.nick && time_difference < 1) {
                msg_css_classes += ' repeated_nick';
            }
        }

        // Build up and add the line
        msg.msg_css_classes = msg_css_classes;
        if (_kiwi.global.settings.get('use_24_hour_timestamps')) {
            msg.time_string = msg.time.getHours().toString().lpad(2, "0") + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0");
        } else {
            hour = msg.time.getHours();
            pm = hour > 11;
            hour = (hour === 0) ? 12 : hour % 12;
            if (pm) {
                msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_pm').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"));
            } else {
                msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_am').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"));
            }
        }
        line_msg = '<div class="msg <%= type %> <%= msg_css_classes %>">
<%- time_string %>
<div class="nick" style="<%= nick_style %>"><%- nick %>
<div class="text" style="<%= style %>"><%= msg %>

';
        this.$messages.append(_.template(line_msg, msg));

        // Activity/alerts based on the type of new message
        if (msg.type.match(/^action /)) {
            this.alert('action');

        } else if (is_highlight) {
            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());
            _kiwi.app.view.favicon.newHighlight();
            _kiwi.app.view.playSound('highlight');
            _kiwi.app.view.showNotification(this.model.get('name'), msg.msg);
            this.alert('highlight');

        } else {
            // If this is the active panel, send an alert out
            if (this.model.isActive()) {
                _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());
            }
            this.alert('activity');
        }

        if (this.model.isQuery() && !this.model.isActive()) {
            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());

            // Highlights have already been dealt with above
            if (!is_highlight) {
                _kiwi.app.view.favicon.newHighlight();
            }

            _kiwi.app.view.showNotification(this.model.get('name'), msg.msg);
            _kiwi.app.view.playSound('highlight');
        }

        // Update the activity counters
        (function () {
            // Only inrement the counters if we're not the active panel
            if (this.model.isActive()) return;

            var $act = this.model.tab.find('.activity'),
                count_all_activity = _kiwi.global.settings.get('count_all_activity'),
                exclude_message_types;

            // Set the default config value
            if (typeof count_all_activity === 'undefined') {
                count_all_activity = false;
            }

            // Do not increment the counter for these message types
            exclude_message_types = [
                'action join',
                'action quit',
                'action part',
                'action kick',
                'action nick',
                'action mode'
            ];

            if (count_all_activity || exclude_message_types.indexOf(msg.type) === -1) {
                $act.text((parseInt($act.text(), 10) || 0) + 1);
            }

            if ($act.text() === '0') {
                $act.addClass('zero');
            } else {
                $act.removeClass('zero');
            }
        }).apply(this);

        if(this.model.isActive()) this.scrollToBottom();

        // Make sure our DOM isn't getting too large (Acts as scrollback)
        this.msg_count++;
        if (this.msg_count > (parseInt(_kiwi.global.settings.get('scrollback'), 10) || 250)) {
            $('.msg:first', this.$messages).remove();
            this.msg_count--;
        }
    },

    topic: function (topic) {
        if (typeof topic !== 'string' || !topic) {
            topic = this.model.get("topic");
        }

        this.model.addMsg('', '== ' + _kiwi.global.i18n.translate('client_views_channel_topic').fetch(this.model.get('name'), topic), 'topic');

        // If this is the active channel then update the topic bar
        if (_kiwi.app.panels().active === this) {
            _kiwi.app.topicbar.setCurrentTopic(this.model.get("topic"));
        }
    },

    // Click on a nickname
    nickClick: function (event) {
        var nick = $(event.currentTarget).text(),
            members = this.model.get('members'),
            are_we_an_op = !!members.getByNick(_kiwi.app.connections.active_connection.get('nick')).get('is_op'),
            member, query, userbox, menubox;

        if (members) {
            member = members.getByNick(nick);
            if (member) {
                userbox = new _kiwi.view.UserBox();
                userbox.setTargets(member, this.model);
                userbox.displayOpItems(are_we_an_op);

                menubox = new _kiwi.view.MenuBox(member.get('nick') || 'User');
                menubox.addItem('userbox', userbox.$el);
                menubox.showFooter(false);
                menubox.show();

                // Position the userbox + menubox
                (function() {
                    var t = event.pageY,
                        m_bottom = t + menubox.$el.outerHeight(),  // Where the bottom of menu will be
                        memberlist_bottom = this.$el.parent().offset().top + this.$el.parent().outerHeight();

                    // If the bottom of the userbox is going to be too low.. raise it
                    if (m_bottom > memberlist_bottom){
                        t = memberlist_bottom - menubox.$el.outerHeight();
                    }

                    // Set the new positon
                    menubox.$el.offset({
                        left: event.clientX,
                        top: t
                    });
                }).call(this);
            }
        }
    },

    chanClick: function (event) {
        var target = (event.target) ? $(event.target).data('channel') : $(event.srcElement).data('channel');

        _kiwi.app.connections.active_connection.gateway.join(target);
    },

    mediaClick: function (event) {
        var $media = $(event.target).parents('.media');
        var media_message;

        if ($media.data('media')) {
            media_message = $media.data('media');
        } else {
            media_message = new _kiwi.view.MediaMessage({el: $media[0]});

            // Cache this MediaMessage instance for when it's opened again
            $media.data('media', media_message);
        }

        media_message.toggle();
    },

    // Cursor hovers over a message
    msgEnter: function (event) {
        var nick_class;

        // Find a valid class that this element has
        _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) {
            if (css_class.match(/^nick_[a-z0-9]+/i)) {
                nick_class = css_class;
            }
        });

        // If no class was found..
        if (!nick_class) return;

        $('.'+nick_class).addClass('global_nick_highlight');
    },

    // Cursor leaves message
    msgLeave: function (event) {
        var nick_class;

        // Find a valid class that this element has
        _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) {
            if (css_class.match(/^nick_[a-z0-9]+/i)) {
                nick_class = css_class;
            }
        });

        // If no class was found..
        if (!nick_class) return;

        $('.'+nick_class).removeClass('global_nick_highlight');
    },
});
<commit_msg>Correctly showing 0 hours in 12 hour timestamps<commit_after>_kiwi.view.Channel = _kiwi.view.Panel.extend({
    events: function(){
        var parent_events = this.constructor.__super__.events;

        if(_.isFunction(parent_events)){
            parent_events = parent_events();
        }
        return _.extend({}, parent_events, {
            'click .msg .nick' : 'nickClick',
            "click .chan": "chanClick",
            'click .media .open': 'mediaClick',
            'mouseenter .msg .nick': 'msgEnter',
            'mouseleave .msg .nick': 'msgLeave'
        });
    },

    initialize: function (options) {
        this.initializePanel(options);

        // Container for all the messages
        this.$messages = $('

');
        this.$el.append(this.$messages);

        this.model.bind('change:topic', this.topic, this);

        if (this.model.get('members')) {
            this.model.get('members').bind('add', function (member) {
                if (member.get('nick') === this.model.collection.network.get('nick')) {
                    this.$el.find('.initial_loader').slideUp(function () {
                        $(this).remove();
                    });
                }
            }, this);
        }

        // Only show the loader if this is a channel (ie. not a query)
        if (this.model.isChannel()) {
            this.$el.append('
 ' + _kiwi.global.i18n.translate('client_views_channel_joining').fetch() + '
');
        }

        this.model.bind('msg', this.newMsg, this);
        this.msg_count = 0;
    },

    render: function () {
        var that = this;

        this.$messages.empty();
        _.each(this.model.get('scrollback'), function (msg) {
            that.newMsg(msg);
        });
    },

    newMsg: function (msg) {
        var re, line_msg,
            nick_colour_hex, nick_hex, is_highlight, msg_css_classes = '',
            time_difference,
            sb = this.model.get('scrollback'),
            prev_msg = sb[sb.length-2],
            network, hour, pm;

        // Nick highlight detecting
        if ((new RegExp('(^|\\W)(' + escapeRegex(_kiwi.app.connections.active_connection.get('nick')) + ')(\\W|$)', 'i')).test(msg.msg)) {
            is_highlight = true;
            msg_css_classes += ' highlight';
        }

        // Escape any HTML that may be in here
        msg.msg =  $('
').text(msg.msg).html();

        // Make the channels clickable
        if ((network = this.model.get('network'))) {
            re = new RegExp('(?:^|\\s)([' + escapeRegex(network.get('channel_prefix')) + '][^ ,\\007]+)', 'g');
            msg.msg = msg.msg.replace(re, function (match) {
                return '' + match + '';
            });
        }

        // Parse any links found
        msg.msg = msg.msg.replace(/(([A-Za-z][A-Za-z0-9\-]*\:\/\/)|(www\.))([\w.\-]+)([a-zA-Z]{2,6})(:[0-9]+)?(\/[\w#!:.?$'()[\]*,;~+=&%@!\-\/]*)?/gi, function (url) {
            var nice = url,
                extra_html = '';

            // Add the http if no protoocol was found
            if (url.match(/^www\./)) {
                url = 'http://' + url;
            }

            // Shorten the displayed URL if it's going to be too long
            if (nice.length > 100) {
                nice = nice.substr(0, 100) + '...';
            }

            // Get any media HTML if supported
            extra_html = _kiwi.view.MediaMessage.buildHtml(url);

            // Make the link clickable
            return '' + nice + '' + extra_html;
        });

        // Convert IRC formatting into HTML formatting
        msg.msg = formatIRCMsg(msg.msg);

        // Replace text emoticons with images
        if (_kiwi.global.settings.get('show_emoticons')) {
            msg.msg = emoticonFromText(msg.msg);
        }

        // Add some colours to the nick (Method based on IRSSIs nickcolor.pl)
        nick_colour_hex = (function (nick) {
            var nick_int = 0, rgb;

            _.map(nick.split(''), function (i) { nick_int += i.charCodeAt(0); });
            rgb = hsl2rgb(nick_int % 255, 70, 35);
            rgb = rgb[2] | (rgb[1] << 8) | (rgb[0] << 16);

            return '#' + rgb.toString(16);
        })(msg.nick);

        msg.nick_style = 'color:' + nick_colour_hex + ';';

        // Generate a hex string from the nick to be used as a CSS class name
        nick_hex = msg.nick_css_class = '';
        if (msg.nick) {
            _.map(msg.nick.split(''), function (char) {
                nick_hex += char.charCodeAt(0).toString(16);
            });
            msg_css_classes += ' nick_' + nick_hex;
        }

        if (prev_msg) {
            // Time difference between this message and the last (in minutes)
            time_difference = (msg.time.getTime() - prev_msg.time.getTime())/1000/60;
            if (prev_msg.nick === msg.nick && time_difference < 1) {
                msg_css_classes += ' repeated_nick';
            }
        }

        // Build up and add the line
        msg.msg_css_classes = msg_css_classes;
        if (_kiwi.global.settings.get('use_24_hour_timestamps')) {
            msg.time_string = msg.time.getHours().toString().lpad(2, "0") + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0");
        } else {
            hour = msg.time.getHours();
            pm = hour > 11;

            hour = hour % 12;
            if (hour === 0)
                hour = 12;

            if (pm) {
                msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_pm').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"));
            } else {
                msg.time_string = _kiwi.global.i18n.translate('client_views_panel_timestamp_am').fetch(hour + ":" + msg.time.getMinutes().toString().lpad(2, "0") + ":" + msg.time.getSeconds().toString().lpad(2, "0"));
            }
        }
        line_msg = '<div class="msg <%= type %> <%= msg_css_classes %>">
<%- time_string %>
<div class="nick" style="<%= nick_style %>"><%- nick %>
<div class="text" style="<%= style %>"><%= msg %>

';
        this.$messages.append(_.template(line_msg, msg));

        // Activity/alerts based on the type of new message
        if (msg.type.match(/^action /)) {
            this.alert('action');

        } else if (is_highlight) {
            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());
            _kiwi.app.view.favicon.newHighlight();
            _kiwi.app.view.playSound('highlight');
            _kiwi.app.view.showNotification(this.model.get('name'), msg.msg);
            this.alert('highlight');

        } else {
            // If this is the active panel, send an alert out
            if (this.model.isActive()) {
                _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());
            }
            this.alert('activity');
        }

        if (this.model.isQuery() && !this.model.isActive()) {
            _kiwi.app.view.alertWindow('* ' + _kiwi.global.i18n.translate('client_views_panel_activity').fetch());

            // Highlights have already been dealt with above
            if (!is_highlight) {
                _kiwi.app.view.favicon.newHighlight();
            }

            _kiwi.app.view.showNotification(this.model.get('name'), msg.msg);
            _kiwi.app.view.playSound('highlight');
        }

        // Update the activity counters
        (function () {
            // Only inrement the counters if we're not the active panel
            if (this.model.isActive()) return;

            var $act = this.model.tab.find('.activity'),
                count_all_activity = _kiwi.global.settings.get('count_all_activity'),
                exclude_message_types;

            // Set the default config value
            if (typeof count_all_activity === 'undefined') {
                count_all_activity = false;
            }

            // Do not increment the counter for these message types
            exclude_message_types = [
                'action join',
                'action quit',
                'action part',
                'action kick',
                'action nick',
                'action mode'
            ];

            if (count_all_activity || exclude_message_types.indexOf(msg.type) === -1) {
                $act.text((parseInt($act.text(), 10) || 0) + 1);
            }

            if ($act.text() === '0') {
                $act.addClass('zero');
            } else {
                $act.removeClass('zero');
            }
        }).apply(this);

        if(this.model.isActive()) this.scrollToBottom();

        // Make sure our DOM isn't getting too large (Acts as scrollback)
        this.msg_count++;
        if (this.msg_count > (parseInt(_kiwi.global.settings.get('scrollback'), 10) || 250)) {
            $('.msg:first', this.$messages).remove();
            this.msg_count--;
        }
    },

    topic: function (topic) {
        if (typeof topic !== 'string' || !topic) {
            topic = this.model.get("topic");
        }

        this.model.addMsg('', '== ' + _kiwi.global.i18n.translate('client_views_channel_topic').fetch(this.model.get('name'), topic), 'topic');

        // If this is the active channel then update the topic bar
        if (_kiwi.app.panels().active === this) {
            _kiwi.app.topicbar.setCurrentTopic(this.model.get("topic"));
        }
    },

    // Click on a nickname
    nickClick: function (event) {
        var nick = $(event.currentTarget).text(),
            members = this.model.get('members'),
            are_we_an_op = !!members.getByNick(_kiwi.app.connections.active_connection.get('nick')).get('is_op'),
            member, query, userbox, menubox;

        if (members) {
            member = members.getByNick(nick);
            if (member) {
                userbox = new _kiwi.view.UserBox();
                userbox.setTargets(member, this.model);
                userbox.displayOpItems(are_we_an_op);

                menubox = new _kiwi.view.MenuBox(member.get('nick') || 'User');
                menubox.addItem('userbox', userbox.$el);
                menubox.showFooter(false);
                menubox.show();

                // Position the userbox + menubox
                (function() {
                    var t = event.pageY,
                        m_bottom = t + menubox.$el.outerHeight(),  // Where the bottom of menu will be
                        memberlist_bottom = this.$el.parent().offset().top + this.$el.parent().outerHeight();

                    // If the bottom of the userbox is going to be too low.. raise it
                    if (m_bottom > memberlist_bottom){
                        t = memberlist_bottom - menubox.$el.outerHeight();
                    }

                    // Set the new positon
                    menubox.$el.offset({
                        left: event.clientX,
                        top: t
                    });
                }).call(this);
            }
        }
    },

    chanClick: function (event) {
        var target = (event.target) ? $(event.target).data('channel') : $(event.srcElement).data('channel');

        _kiwi.app.connections.active_connection.gateway.join(target);
    },

    mediaClick: function (event) {
        var $media = $(event.target).parents('.media');
        var media_message;

        if ($media.data('media')) {
            media_message = $media.data('media');
        } else {
            media_message = new _kiwi.view.MediaMessage({el: $media[0]});

            // Cache this MediaMessage instance for when it's opened again
            $media.data('media', media_message);
        }

        media_message.toggle();
    },

    // Cursor hovers over a message
    msgEnter: function (event) {
        var nick_class;

        // Find a valid class that this element has
        _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) {
            if (css_class.match(/^nick_[a-z0-9]+/i)) {
                nick_class = css_class;
            }
        });

        // If no class was found..
        if (!nick_class) return;

        $('.'+nick_class).addClass('global_nick_highlight');
    },

    // Cursor leaves message
    msgLeave: function (event) {
        var nick_class;

        // Find a valid class that this element has
        _.each($(event.currentTarget).parent('.msg').attr('class').split(' '), function (css_class) {
            if (css_class.match(/^nick_[a-z0-9]+/i)) {
                nick_class = css_class;
            }
        });

        // If no class was found..
        if (!nick_class) return;

        $('.'+nick_class).removeClass('global_nick_highlight');
    },
});
<|endoftext|>


<commit_before>var router = require('express').Router();
router.route('/')
.post(function(req, res) {
  var newPostKey = req.body.key || global.db.ref().child('clients').push().key;
  res.json(global.db.ref('clients/' + newPostKey).set(req.body).key);
})
.get(function(req, res) {
  var search = 'clients/' + (req.query.key || '');
  global.db.ref(search).once('value').then(function(snapshot) {
    res.json(snapshot.val());
  });
})
;
router.route('/wait-list')
.get(function(req, res) {
  global.db.ref('intake/').once('value').then(function(snapshot) {
    var intakes = snapshot.val();
    var responseList = [];
    if(intakes){
      var intakesKeyList = Object.keys(intakes);
      var dataLength = intakesKeyList.length;
      for (var i = 0; i < dataLength; i++) {
        var key = intakesKeyList[i];
        var keyData = intakes[key];
        responseObj = {};
        responseObj.firstName = keyData.responses.firstName.answer;
        responseObj.lastName = keyData.responses.lastName.answer;
        responseObj.phoneNumber = keyData.phone;
        responseObj.onStreets = keyData.responses.onStreets.answer;
        responseList.push(responseObj);
      }
    }
    res.json(responseList);
  })
})
module.exports = router;
<commit_msg>Update so phone call ins are stored differently<commit_after>var router = require('express').Router();
router.route('/')
.post(function(req, res) {
  var newPostKey = req.body.key || global.db.ref().child('clients').push().key;
  res.json(global.db.ref('clients/' + newPostKey).set(req.body).key);
})
.get(function(req, res) {
  var search = 'clients/' + (req.query.key || '');
  global.db.ref(search).once('value').then(function(snapshot) {
    res.json(snapshot.val());
  });
})
;
router.route('/wait-list')
.get(function(req, res) {
  global.db.ref('intake/').once('value').then(function(snapshot) {
    var intakes = snapshot.val();
    var responseList = [];
    if(intakes){
      var intakesKeyList = Object.keys(intakes);
      var dataLength = intakesKeyList.length;
      for (var i = 0; i < dataLength; i++) {
        var key = intakesKeyList[i];
        var keyData = intakes[key];
        responseObj = {};
        if(keyData.responses.firstName.answer) {
          responseObj.firstName = keyData.responses.firstName.answer || '';
          responseObj.lastName = keyData.responses.lastName.answer || '';
          responseObj.phoneNumber = keyData.phone || '';
          responseObj.onStreets = keyData.responses.onStreets.answer || '';
        }
        responseObj.conversationCode = key;
        responseObj.phoneNumber = keyData.phone;
        responseList.push(responseObj);
      }
    }
    res.json(responseList);
  })
})
module.exports = router;
<|endoftext|>


<commit_before>/* global ButtonList, w2, h2, Adventure, Phaser */
var levelSelector = function (game) {
  this.title = null
  this.buttons = null
  this.containerScrollBar = null
  this.scrollMask = null
  this.containerX = 0
  this.containerY = 0
}

levelSelector.prototype = {
  create: function () {
    this.title = this.game.add.text(w2, 100, 'Level Selector', {
      font: '150px dosis',
      fill: '#ffffff',
      align: 'center'
    })
    this.title.anchor.setTo(0.5, 0.5)

    this.containerX = 1.5 * w2
    this.containerY = 300

    this.buttons = new ButtonList(this, this.game)

    this.buttons.add('back_button', 'back', this.backPressed)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)

    this.buttons.create()
    this.buttons.select(1)

    this.containerScrollBar = this.game.add.sprite(this.containerX, this.containerY - 50, 'scroll_button')
    this.containerScrollBar.scale.set(50, 100)
    this.containerScrollBar.anchor.set(1, 0.5)

    this.scrollMask = this.game.add.graphics(0, 0)
    this.scrollMask.beginFill(0xffffff)
    this.scrollMask.drawRect(w2 * 0.5, this.containerY - 100, w2 * 2, h2 * 1.2)
    this.scrollMask.endFill()

    this.containerScrollBar.mask = this.scrollMask
    this.containerScrollBar.inputEnabled = true
    this.containerScrollBar.input.useHandCursor = true
    this.containerScrollBar.input.enableDrag(false, true)
    this.containerScrollBar.input.allowHorizontalDrag = false
    this.containerScrollBar.input.boundsRect = new Phaser.Rectangle(this.containerX - this.containerScrollBar.width, this.containerY - 100, 5000, h2 * 1.2)
  },

  update: function () {
    this.buttons.setY(2 * this.containerY - this.containerScrollBar.y - 100)
    this.buttons.update()
  },

  play: function () {
    var mode = new Adventure(this.game, false)
    this.game.state.start('PreloadGame', true, false, mode, 'assets/levels/level1')
  },

  backPressed: function () {
    this.game.state.start('Menu')
  },

  up: function () {
    this.buttons.selectUp()
  },

  down: function () {
    this.buttons.selectDown()
  },

  selectPress: function () {
    this.buttons.selectPress()
  },

  selectRelease: function () {
    this.buttons.selectRelease()
  }

}
<commit_msg>scrollBar v4<commit_after>/* global ButtonList, w2, h2, Adventure, Phaser */
var levelSelector = function (game) {
  this.title = null
  this.buttons = null
  this.containerScrollBar = null
  this.scrollMask = null
  this.containerX = 0
  this.containerY = 0
}

levelSelector.prototype = {
  create: function () {
    this.title = this.game.add.text(w2, 100, 'Level Selector', {
      font: '150px dosis',
      fill: '#ffffff',
      align: 'center'
    })
    this.title.anchor.setTo(0.5, 0.5)

    this.containerX = 1.5 * w2
    this.containerY = 300

    this.buttons = new ButtonList(this, this.game)

    this.buttons.add('back_button', 'back', this.backPressed)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)
    this.buttons.add('accept_button', 'play', this.play)

    this.buttons.create()
    this.buttons.select(1)

    this.containerScrollBar = this.game.add.sprite(this.containerX, this.containerY - 50, 'scroll_button')
    this.containerScrollBar.scale.set(50, 100)
    this.containerScrollBar.anchor.set(1, 0.5)

    this.scrollMask = this.game.add.graphics(0, 0)
    this.scrollMask.beginFill(0xffffff)
    this.scrollMask.drawRect(w2 * 0.5, this.containerY - 100, w2 * 2, h2 * 2)
    this.scrollMask.endFill()

    this.buttons.setMask(this.scrollMask)

    this.containerScrollBar.inputEnabled = true
    this.containerScrollBar.input.useHandCursor = true
    this.containerScrollBar.input.enableDrag(false, true)
    this.containerScrollBar.input.allowHorizontalDrag = false
    this.containerScrollBar.input.boundsRect = new Phaser.Rectangle(this.containerX - this.containerScrollBar.width, this.containerY - 100, 5000, h2 * 1.2)
  },

  update: function () {
    this.buttons.setY(2 * this.containerY - this.containerScrollBar.y - 100)
    this.buttons.update()
  },

  play: function () {
    var mode = new Adventure(this.game, false)
    this.game.state.start('PreloadGame', true, false, mode, 'assets/levels/level1')
  },

  backPressed: function () {
    this.game.state.start('Menu')
  },

  up: function () {
    this.buttons.selectUp()
  },

  down: function () {
    this.buttons.selectDown()
  },

  selectPress: function () {
    this.buttons.selectPress()
  },

  selectRelease: function () {
    this.buttons.selectRelease()
  }

}
<|endoftext|>


<commit_before>import { expect } from 'chai';
import List from '../src/List';

describe('List.js', () => {
  describe('List.each', () => {
    it('Should apply a function to each item in a list, not returning any value', () => {
      const input = [1, 2, 3, 4, 5];
      const output = [];
      const expected = [2, 3, 4, 5, 6];
      List.each((x) => output.push(++x), input);
      expect(output).to.deep.equal(expected);
    });
  });

  describe('List.map', () => {
    it('Should apply a function to each item in a list, returning a new list with the result', () => {
      const input = [1, 2, 3, 4, 5];
      expect(List.map((x) => ++x, input)).to.deep.equal([2, 3, 4, 5, 6]);
      expect(List.map((x) => ++x)(input)).to.deep.equal([2, 3, 4, 5, 6]);
    });
  });

  describe('List.compact', () => {
    it('Should return a list of truthy values in a list', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.compact(input)).to.deep.equal([true, 1, 2, 4, 5]);
    });
  });

  describe('List.filter', () => {
    it('Should return the values in a list that satisfy a given predicate', () => {
      const input = [0, 1, 2, 3, 4, 5];
      expect(List.filter((x) => x > 3, input)).to.deep.equal([4, 5]);
    });
  });

  describe('List.reject', () => {
    it('Should return the values in a list that doesn\'t satisfy the given predicate', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.reject((x) => x, input)).to.deep.equal([0, false]);
    });
  });

  describe('List.partition', () => {
    it('Should return a list with two lists containing the passed and failed values given a predicate', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.partition((x) => x, input)).to.deep.equal([[true, 1, 2, 4, 5], [0, false]]);
    });
  });

  describe('List.find', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the exact value in a list that satisfies a given predicate', () => {
      expect(List.find((x) => x === 4, input)).to.equal(4);
    });
    it('Should return the first value in a list that satisfies an ambiguous predicate', () => {
      expect(List.find((x) => x > 2, input)).to.equal(3);
    });
    it('Should return undefined when no value in a list satisfies a given predicate', () => {
      expect(List.find((x) => x === 12, input)).to.equal(undefined);
    });
  });

  describe('List.head', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the first value in a list', () => {
      expect(List.head(input)).to.equal(1);
    });
  });

  describe('List.first (alias => List.head)', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the first value in a list', () => {
      expect(List.first(input)).to.equal(1);
    });
  });

  describe('List.tail', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return all but the first value in a list', () => {
      expect(List.tail(input)).to.deep.equal([2, 3, 4, 5]);
    });
  });

  describe('List.last', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the last value in a list', () => {
      expect(List.last(input)).to.equal(5);
    });
  });

  describe('List.initial', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return all but the last value in a list', () => {
      expect(List.initial(input)).to.deep.equal([1, 2, 3, 4]);
    });
  });

  describe('List.empty', () => {
    it('Should return true for an empty list', () => {
      expect(List.empty([])).to.equal(true);
    });
    it('Should return false for an non-empty list', () => {
      expect(List.empty([1, 2, 3])).to.equal(false);
    });
  });

  describe('List.reverse', () => {
    const input = [1, 2, 0, 5, 4, 3];
    it('Should return the items in a list in a reversed order', () => {
      expect(List.reverse(input)).to.deep.equal([3, 4, 5, 0, 2, 1]);
      expect(List.reverse(input)).to.deep.equal(input.reverse());
    });
  });

  describe('List.uniqueBy', () => {
    it('Should find the unique items in a list given a predicate', () => {
      const input = [
        { color: 'orange' },
        { color: 'green' },
        { color: 'orange' },
        { color: 'blue' },
        { color: 'green' },
        { color: 'orange' }
      ];
      expect(List.uniqueBy((x) => x.color, input)).to.deep.equal(['orange', 'green', 'blue']);
    });
  });

  describe('List.unique', () => {
    it('Should find the unique items in a list', () => {
      const input = [1, 2, 3, 2, 2, 1, 3, 2, 0, 9];
      expect(List.unique(input)).to.deep.equal([1, 2, 3, 0, 9]);
    });
  });
});
<commit_msg>fold functions tests - WIP<commit_after>import { expect } from 'chai';
import List from '../src/List';

describe('List.js', () => {
  describe('List.each', () => {
    it('Should apply a function to each item in a list, not returning any value', () => {
      const input = [1, 2, 3, 4, 5];
      const output = [];
      const expected = [2, 3, 4, 5, 6];
      List.each((x) => output.push(++x), input);
      expect(output).to.deep.equal(expected);
    });
  });

  describe('List.map', () => {
    it('Should apply a function to each item in a list, returning a new list with the result', () => {
      const input = [1, 2, 3, 4, 5];
      expect(List.map((x) => ++x, input)).to.deep.equal([2, 3, 4, 5, 6]);
      expect(List.map((x) => ++x)(input)).to.deep.equal([2, 3, 4, 5, 6]);
    });
  });

  describe('List.compact', () => {
    it('Should return a list of truthy values in a list', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.compact(input)).to.deep.equal([true, 1, 2, 4, 5]);
    });
  });

  describe('List.filter', () => {
    it('Should return the values in a list that satisfy a given predicate', () => {
      const input = [0, 1, 2, 3, 4, 5];
      expect(List.filter((x) => x > 3, input)).to.deep.equal([4, 5]);
    });
  });

  describe('List.reject', () => {
    it('Should return the values in a list that doesn\'t satisfy the given predicate', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.reject((x) => x, input)).to.deep.equal([0, false]);
    });
  });

  describe('List.partition', () => {
    it('Should return a list with two lists containing the passed and failed values given a predicate', () => {
      const input = [0, true, 1, 2, false, 4, 5];
      expect(List.partition((x) => x, input)).to.deep.equal([[true, 1, 2, 4, 5], [0, false]]);
    });
  });

  describe('List.find', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the exact value in a list that satisfies a given predicate', () => {
      expect(List.find((x) => x === 4, input)).to.equal(4);
    });
    it('Should return the first value in a list that satisfies an ambiguous predicate', () => {
      expect(List.find((x) => x > 2, input)).to.equal(3);
    });
    it('Should return undefined when no value in a list satisfies a given predicate', () => {
      expect(List.find((x) => x === 12, input)).to.equal(undefined);
    });
  });

  describe('List.head', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the first value in a list', () => {
      expect(List.head(input)).to.equal(1);
    });
  });

  describe('List.first (alias => List.head)', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the first value in a list', () => {
      expect(List.first(input)).to.equal(1);
    });
  });

  describe('List.tail', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return all but the first value in a list', () => {
      expect(List.tail(input)).to.deep.equal([2, 3, 4, 5]);
    });
  });

  describe('List.last', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return the last value in a list', () => {
      expect(List.last(input)).to.equal(5);
    });
  });

  describe('List.initial', () => {
    const input = [1, 2, 3, 4, 5];
    it('Should return all but the last value in a list', () => {
      expect(List.initial(input)).to.deep.equal([1, 2, 3, 4]);
    });
  });

  describe('List.empty', () => {
    it('Should return true for an empty list', () => {
      expect(List.empty([])).to.equal(true);
    });
    it('Should return false for an non-empty list', () => {
      expect(List.empty([1, 2, 3])).to.equal(false);
    });
  });

  describe('List.reverse', () => {
    const input = [1, 2, 0, 5, 4, 3];
    it('Should return the items in a list in a reversed order', () => {
      expect(List.reverse(input)).to.deep.equal([3, 4, 5, 0, 2, 1]);
      expect(List.reverse(input)).to.deep.equal(input.reverse());
    });
  });

  describe('List.uniqueBy', () => {
    it('Should find the unique items in a list given a predicate', () => {
      const input = [
        { color: 'orange' },
        { color: 'green' },
        { color: 'orange' },
        { color: 'blue' },
        { color: 'green' },
        { color: 'orange' }
      ];
      expect(List.uniqueBy((x) => x.color, input)).to.deep.equal(['orange', 'green', 'blue']);
    });
  });

  describe('List.unique', () => {
    it('Should find the unique items in a list', () => {
      const input = [1, 2, 3, 2, 2, 1, 3, 2, 0, 9];
      expect(List.unique(input)).to.deep.equal([1, 2, 3, 0, 9]);
    });
  });

  describe('List.foldl', () => {
    it('Should calculate the sum of items in a list', () => {
      const input = [1, 2, 3, 4, 5, 6, 7, 8, 9];
      expect(List.foldl((x, y) => x + y, 0, input)).to.equal(45);
    });
  });

  describe('List.foldl1', () => {
    it('Should calculate the number of items in a list', () => {
      const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
      expect(List.foldl1((x) => x + 1, input)).to.equal(10);
    });
  });

  describe('List.foldr', () => {
    it('Should concatenate the letters with the initial value', () => {
      const input = ['h', 'e', 'l', 'l'];
      expect(List.foldr((x, y) => x + y, 'o')(input)).to.equal('hello');
    });
  });

  describe('List.foldr1', () => {
    it('Should calculate the number of items in a list', () => {
      const input = [1, 2, 3, 4, 9];
      expect(List.foldr1((x, y) => x - y, input)).to.equal(7);
    });
  });
});
<|endoftext|>


<commit_before>var url = require('url'),
	https = require('https'),
	assert = require('assert');

exports.api = function(login, password, config) {
	"use strict";
	assert.equal(typeof(login), 'string', "argument 'login' must be a string");
	assert.equal(typeof(password), 'string', "argument 'password' must be a string");

	var SDK_VERSION = "1.1";

	// var LogAs types
	var loginAsTypes = {
		user: 'user.login',
		account: 'account.hash'
	}

	// allow api url to be changed
	this.apiUrl = "https://api.callr.com/json-rpc/v1.1/";

	// Callback class
	var Callback = function() {
		this.success = false;
		this.error = false;
	};

	// Send a request to THECALLR webservice
	this.call = function(method) {
		assert.equal(typeof(method), 'string', "argument 'method' must be a string");

		var args = Array.prototype.slice.call(arguments);
		return this.send(method, args.slice(1, args.length));
	};

	// Send a request to THECALLR webservice
	this.send = function(method, params, id) {
		assert.equal(typeof(method), 'string', "argument 'method' must be a string");
		assert.ok(params instanceof(Array), "argument 'params' must be an array");

		var json = JSON.stringify({
			id: id === undefined || isNaN(parseInt(id)) ? Math.floor(Math.random() * (999 - 100)) + 100 : id,
			jsonrpc: "2.0",
			method: method,
			params: params instanceof Array ? params : []
		});

		var options = url.parse(this.apiUrl);
		options.port = 443;
		options.method = "POST";
		options.auth = login + ':' + password;
		options.headers = {
			"Content-Type": "application/json-rpc; charset=utf-8",
			"User-Agent": "sdk=NODE; sdk-version="+SDK_VERSION+"; lang-version="+process.version+"; platform="+process.platform,
			"Content-Length": Buffer.byteLength(json)
		};

		// Login As support
		if (config && config.hasOwnProperty('loginas')) {
			assert.equal(typeof (config.loginas.type), 'string', "loginas.type must be a string");
			assert.ok(config.loginas.type.toLowerCase() in loginAsTypes, `loginas type must be one of "${Object.keys(loginAsTypes)}"`);
			assert.equal(typeof (config.loginas.target), 'string', "loginas.target must be a string")

			options.headers['CALLR-Login-As'] = `${loginAsTypes[config.loginas.type.toLowerCase()]} ${config.loginas.target}`;
		}

		// Proxy agent support
		if (config && config.hasOwnProperty('proxyAgent')) {
			options.agent = config.proxyAgent;
		}

		this.callback = new Callback();

		// Annonymous Closure to keep data untouched on successive call
		(function(options, json, callback) {
			// make new request
			var req = https.request(options, function(res) {
				var buf = "";
				if (res.statusCode != 200) {
					doCallback(callback.error, error("HTTP_CODE_ERROR", -1, {
						http_code: res.statusCode
					}));
				}
				res.on('data', function(data) {
					buf += data;
				});
				res.on('end', function() {
					parseData(buf.toString(), callback);
				});
			});

			req.on('error', function(e) {
				doCallback(callback.error, error("HTTP_EXCEPTION", -1, {
					exception: e
				}));
			}).on('end', function() {
				console.log('request end');
			}).end(json);
		})(options, json, this.callback);

		return this;
	};

	// set success callback
	this.success = function(cb) {
		this.callback.success = cb;
		return this;
	};

	// set error callback
	this.error = function(cb) {
		this.callback.error = cb;
		return this;
	};

	// Response analysis
	function parseData(json, callback) {
		try {
			var data = JSON.parse(json);
			if (data && data.hasOwnProperty('result'))
				doCallback(callback.success, data.result);
			else if (data && data.hasOwnProperty('error') && data.error)
				doCallback(callback.error, error(data.error.message, data.error.code, null));
			else
				doCallback(callback.error, error("INVALID_RESPONSE", -1, {
					responses: json.toString()
				}));
		}
		catch (e) {
			doCallback(callback.error, error("INVALID_RESPONSE", -1, {
				exception: e,
				response: json.toString()
			}));
		}
	}

	function doCallback(callback, result) {
		if (typeof(callback) == 'function')
			callback(result);
	}

	function error(msg, code, data) {
		var err = new Error(msg);
		err.code = code;
		err.data = data;
		return err;
	}
};
<commit_msg>add setLoginAs function<commit_after>var url = require('url'),
	https = require('https'),
	assert = require('assert');

exports.api = function(login, password, config) {
	"use strict";
	assert.equal(typeof(login), 'string', "argument 'login' must be a string");
	assert.equal(typeof(password), 'string', "argument 'password' must be a string");

	var SDK_VERSION = "1.1";

	// var LogAs types
	var loginAsTypes = {
		user: 'user.login',
		account: 'account.hash'
	}

	// allow api url to be changed
	this.apiUrl = "https://api.callr.com/json-rpc/v1.1/";

	// Callback class
	var Callback = function() {
		this.success = false;
		this.error = false;
	};

	// Set login As options
	this.setLoginAs = function (type, target) {
		if(config === undefined) config = {};
		config.loginas = {
			type: type,
			target: target
		}
	}

	// Send a request to THECALLR webservice
	this.call = function(method) {
		assert.equal(typeof(method), 'string', "argument 'method' must be a string");

		var args = Array.prototype.slice.call(arguments);
		return this.send(method, args.slice(1, args.length));
	};

	// Send a request to THECALLR webservice
	this.send = function(method, params, id) {
		assert.equal(typeof(method), 'string', "argument 'method' must be a string");
		assert.ok(params instanceof(Array), "argument 'params' must be an array");

		var json = JSON.stringify({
			id: id === undefined || isNaN(parseInt(id)) ? Math.floor(Math.random() * (999 - 100)) + 100 : id,
			jsonrpc: "2.0",
			method: method,
			params: params instanceof Array ? params : []
		});

		var options = url.parse(this.apiUrl);
		options.port = 443;
		options.method = "POST";
		options.auth = login + ':' + password;
		options.headers = {
			"Content-Type": "application/json-rpc; charset=utf-8",
			"User-Agent": "sdk=NODE; sdk-version="+SDK_VERSION+"; lang-version="+process.version+"; platform="+process.platform,
			"Content-Length": Buffer.byteLength(json)
		};

		// Login As support
		if (config && config.hasOwnProperty('loginas')) {
			assert.equal(typeof (config.loginas.type), 'string', "loginas.type must be a string");
			assert.ok(config.loginas.type.toLowerCase() in loginAsTypes, `loginas type must be one of "${Object.keys(loginAsTypes)}"`);
			assert.equal(typeof (config.loginas.target), 'string', "loginas.target must be a string")

			options.headers['CALLR-Login-As'] = `${loginAsTypes[config.loginas.type.toLowerCase()]} ${config.loginas.target}`;
		}

		// Proxy agent support
		if (config && config.hasOwnProperty('proxyAgent')) {
			options.agent = config.proxyAgent;
		}

		this.callback = new Callback();

		// Annonymous Closure to keep data untouched on successive call
		(function(options, json, callback) {
			// make new request
			var req = https.request(options, function(res) {
				var buf = "";
				if (res.statusCode != 200) {
					doCallback(callback.error, error("HTTP_CODE_ERROR", -1, {
						http_code: res.statusCode
					}));
				}
				res.on('data', function(data) {
					buf += data;
				});
				res.on('end', function() {
					parseData(buf.toString(), callback);
				});
			});

			req.on('error', function(e) {
				doCallback(callback.error, error("HTTP_EXCEPTION", -1, {
					exception: e
				}));
			}).on('end', function() {
				console.log('request end');
			}).end(json);
		})(options, json, this.callback);

		return this;
	};

	// set success callback
	this.success = function(cb) {
		this.callback.success = cb;
		return this;
	};

	// set error callback
	this.error = function(cb) {
		this.callback.error = cb;
		return this;
	};

	// Response analysis
	function parseData(json, callback) {
		try {
			var data = JSON.parse(json);
			if (data && data.hasOwnProperty('result'))
				doCallback(callback.success, data.result);
			else if (data && data.hasOwnProperty('error') && data.error)
				doCallback(callback.error, error(data.error.message, data.error.code, null));
			else
				doCallback(callback.error, error("INVALID_RESPONSE", -1, {
					responses: json.toString()
				}));
		}
		catch (e) {
			doCallback(callback.error, error("INVALID_RESPONSE", -1, {
				exception: e,
				response: json.toString()
			}));
		}
	}

	function doCallback(callback, result) {
		if (typeof(callback) == 'function')
			callback(result);
	}

	function error(msg, code, data) {
		var err = new Error(msg);
		err.code = code;
		err.data = data;
		return err;
	}
};
<|endoftext|>


<commit_before>var createSpec = require('spec-js'),
    EventEmitter = require('events').EventEmitter,
    merge = require('./flatMerge'),
    jsonConverter = require('./jsonConverter');

var stack = [];
function eventually(fn){
    stack.push(fn);
    if(stack.length === 1){
        setTimeout(function(){
            while(stack.length){
                stack.pop()();
            }
        },100);
    }
}

function getItemPath(item){
    var gedi = item.gaffa.gedi,
        paths = [],
        referencePath,
        referenceItem = item;

    while(referenceItem){

        // item.path should be a child ref after item.sourcePath
        if(referenceItem.path != null){
            paths.push(referenceItem.path);
            if(gedi.paths.isAbsolute(referenceItem.path)){
                break;
            }
        }

        // item.sourcePath is most root level path
        if(referenceItem.sourcePath != null){
            paths.push(gedi.paths.create(referenceItem.sourcePath));
        }

        referenceItem = referenceItem.parent;
    }

    return gedi.paths.resolve.apply(this, paths.reverse());
}

var iuid = 0;

function Bindable(){
    this.setMaxListeners(1000);
    // instance unique ID
    this.__iuid = iuid++;
}
Bindable = createSpec(Bindable, EventEmitter);
Bindable.bindables = {};
Bindable.getByIuid = function(id){
    return this.bindables[id];
};
Bindable.prototype.getPath = function(){
    return getItemPath(this);
};
Bindable.prototype.getDataAtPath = function(){
    if(!this.gaffa){
        return;
    }
    return this.gaffa.model.get(getItemPath(this));
};
Bindable.prototype.toJSON = function(){
    var tempObject = jsonConverter(this, this.__serialiseExclude__, this.__serialiseInclude__);

    return tempObject;
};

function setupCleanup(bindable, parent){
    var onDebind = bindable.debind.bind(bindable);
    parent.once('debind', onDebind);
    bindable.once('debind', function(){
        bindable.parent.removeListener('debind', onDebind);
    });

    var onDestroy = bindable.destroy.bind(bindable);
    parent.once('destroy', onDestroy);
    bindable.once('destroy', function(){
        bindable.parent.removeListener('destroy', onDestroy);
    });
}

Bindable.prototype.bind = function(parent, scope){
    if(scope){
        this.scope = merge(scope, this.scope);
    }

    if(parent && !parent._bound){
        console.warn('Attempted to bind to a parent who was not bound.');
        return;
    }
    if(this._bound){
        this.debind();
        console.warn('Attempted to bind an already bound item.');
    }

    if(parent){
        this.gaffa = parent.gaffa;
        this.parent = parent;
        this._parentId = parent.__iuid;

        setupCleanup(this, parent);
    }

    this.updatePath();

    if('path' in this && !this.path){
        this._invalidPath = true;
        return;
    }

    this._bound = true;
    Bindable.bindables[this.__iuid] = this;
    this.emit('bind', parent, scope);
};
Bindable.prototype.getSourcePath = function(){
    return this.gaffa.gedi.paths.resolve(this.parent && this.parent.getPath(), this.sourcePath);
}
Bindable.prototype.updatePath = function(){
    if(!this.pathBinding || this._pathBindingBound){
        return;
    }

    this._pathBindingBound = true;

    var bindable = this,
        absoluteSourcePath = this.getSourcePath(),
        lastPath = this.path,
        gaffa = this.gaffa;

    function setPath(valueTokens){
        if(valueTokens){
            var valueToken = valueTokens[valueTokens.length - 1];
            bindable.path = valueToken.sourcePathInfo && valueToken.sourcePathInfo.path;
        }

        if(lastPath !== bindable.path){
            lastPath = bindable.path;

            if(bindable._bound || bindable._invalidPath){
                bindable.debind();

                if(bindable.path == null){
                    bindable._invalidPath = true;
                    return;
                }

                bindable._invalidPath = false;

                bindable.bind(bindable.parent, bindable.scope);
            }
        }
    }

    setPath(gaffa.gedi.get(this.pathBinding, absoluteSourcePath, bindable.scope, true));

    function handlePathChange(event){
        setPath(gaffa.model.get(bindable.pathBinding, bindable, bindable.scope, true));
    }

    gaffa.gedi.bind(this.pathBinding, handlePathChange, absoluteSourcePath);
    this.on('destroy', function(){
        gaffa.gedi.debind(bindable.pathBinding, handlePathChange, absoluteSourcePath);
    });
};
Bindable.prototype.debind = function(){
    var bindable = this;

    if(!this._bound){
        // ToDo: This happens with actions, resolve.
        return;
    }
    this._bound = false;

    this.emit('debind');
    delete Bindable.bindables[this.__iuid];
};
Bindable.prototype.destroy = function(){
    var bindable = this;

    this._destroyed = true;

    if(this._bound){
        this.debind();
    }

    for(var key in this){
        if(key !== 'parent' && this[key] instanceof Bindable && this[key]._bound){
            console.log(key);
        }
    }

    // Destroy bindables asynchonously.
    eventually(function(){

        bindable.emit('destroy');
        bindable.removeAllListeners();

        // Let any children bound to 'destroy' do their thing before actually destroying this.
        eventually(function(){
            bindable.gaffa = null;
            bindable.parent = null;
        });
    });
};

module.exports = Bindable;<commit_msg>fixed order of debinding, pathBinding changes<commit_after>var createSpec = require('spec-js'),
    EventEmitter = require('events').EventEmitter,
    merge = require('./flatMerge'),
    jsonConverter = require('./jsonConverter');

var stack = [];
function eventually(fn){
    stack.push(fn);
    if(stack.length === 1){
        setTimeout(function(){
            while(stack.length){
                stack.pop()();
            }
        },100);
    }
}

function getItemPath(item){
    var gedi = item.gaffa.gedi,
        paths = [],
        referenceItem = item;

    while(referenceItem){

        // item.path should be a child ref after item.sourcePath
        if(referenceItem.path != null){
            paths.push(referenceItem.path);
            if(gedi.paths.isAbsolute(referenceItem.path)){
                break;
            }
        }

        // item.sourcePath is most root level path
        if(referenceItem.sourcePath != null){
            paths.push(gedi.paths.create(referenceItem.sourcePath));
        }

        referenceItem = referenceItem.parent;
    }

    return gedi.paths.resolve.apply(this, paths.reverse());
}

var iuid = 0;

function Bindable(){
    this.setMaxListeners(1000);
    // instance unique ID
    this.__iuid = iuid++;
}
Bindable = createSpec(Bindable, EventEmitter);
Bindable.bindables = {};
Bindable.getByIuid = function(id){
    return this.bindables[id];
};
Bindable.prototype.getPath = function(){
    return getItemPath(this);
};
Bindable.prototype.getDataAtPath = function(){
    if(!this.gaffa){
        return;
    }
    return this.gaffa.model.get(getItemPath(this));
};
Bindable.prototype.toJSON = function(){
    var tempObject = jsonConverter(this, this.__serialiseExclude__, this.__serialiseInclude__);

    return tempObject;
};

function setupCleanup(bindable, parent){
    var onDebind = bindable.debind.bind(bindable);
    parent.once('debind', onDebind);
    bindable.once('debind', function(){
        bindable.parent.removeListener('debind', onDebind);
    });

    var onDestroy = bindable.destroy.bind(bindable);
    parent.once('destroy', onDestroy);
    bindable.once('destroy', function(){
        bindable.parent.removeListener('destroy', onDestroy);
    });
}

Bindable.prototype.bind = function(parent, scope){
    if(scope){
        this.scope = merge(scope, this.scope);
    }

    if(parent && !parent._bound){
        console.warn('Attempted to bind to a parent who was not bound.');
        return;
    }
    if(this._bound){
        this.debind();
        console.warn('Attempted to bind an already bound item.');
    }

    if(parent){
        this.gaffa = parent.gaffa;
        this.parent = parent;
        this._parentId = parent.__iuid;

        setupCleanup(this, parent);
    }

    this.updatePath();

    if('path' in this && !this.path){
        this._invalidPath = true;
        return;
    }

    this._bound = true;
    Bindable.bindables[this.__iuid] = this;
    this.emit('bind', parent, scope);
};
Bindable.prototype.getSourcePath = function(){
    return this.gaffa.gedi.paths.resolve(this.parent && this.parent.getPath(), this.sourcePath);
};
Bindable.prototype.updatePath = function(){
    if(!this.pathBinding || this._pathBindingBound){
        return;
    }

    this._pathBindingBound = true;

    var bindable = this,
        absoluteSourcePath = this.getSourcePath(),
        lastPath = this.path,
        gaffa = this.gaffa;

    function setPath(valueTokens){
        var newPath;

        if(valueTokens){
            var valueToken = valueTokens[valueTokens.length - 1];
            newPath = valueToken.sourcePathInfo && valueToken.sourcePathInfo.path;
        }

        if(newPath === lastPath){
            return;
        }

        lastPath = newPath;

        if(!bindable._bound && !bindable._invalidPath){
            bindable.path = newPath;
            return;
        }

        bindable.debind();
        bindable.path = newPath;

        if(newPath == null){
            bindable._invalidPath = true;
            return;
        }

        bindable._invalidPath = false;
        bindable.bind(bindable.parent, bindable.scope);
    }

    setPath(gaffa.gedi.get(this.pathBinding, absoluteSourcePath, bindable.scope, true));

    function handlePathChange(event){
        setPath(gaffa.model.get(bindable.pathBinding, bindable, bindable.scope, true));
    }

    gaffa.gedi.bind(this.pathBinding, handlePathChange, absoluteSourcePath);
    this.on('destroy', function(){
        gaffa.gedi.debind(bindable.pathBinding, handlePathChange, absoluteSourcePath);
    });
};
Bindable.prototype.debind = function(){
    var bindable = this;

    if(!this._bound){
        // ToDo: This happens with actions, resolve.
        return;
    }

    this.emit('debind');

    this._bound = false;

    delete Bindable.bindables[this.__iuid];
};
Bindable.prototype.destroy = function(){
    var bindable = this;

    this._destroyed = true;

    if(this._bound){
        this.debind();
    }

    for(var key in this){
        if(key !== 'parent' && this[key] instanceof Bindable && this[key]._bound){
            console.log(key);
        }
    }

    // Destroy bindables asynchonously.
    eventually(function(){

        bindable.emit('destroy');
        bindable.removeAllListeners();

        // Let any children bound to 'destroy' do their thing before actually destroying this.
        eventually(function(){
            bindable.gaffa = null;
            bindable.parent = null;
        });
    });
};

module.exports = Bindable;
<|endoftext|>


<commit_before>import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { Users } from '/imports/api/user/UserCollection';
import { Opportunities } from '/imports/api/opportunity/OpportunityCollection';
import { Courses } from '/imports/api/course/CourseCollection';
import { Semesters } from '/imports/api/semester/SemesterCollection';
import { Slugs } from '/imports/api/slug/SlugCollection';

import BaseInstanceCollection from '/imports/api/base/BaseInstanceCollection';

/** @module Feed */

/**
 * Represents a feed instance.
 * @extends module:BaseInstance~BaseInstanceCollection
 */
class FeedCollection extends BaseInstanceCollection {

  /**
   * Creates the Feed collection.
   */
  constructor() {
    super('Feed', new SimpleSchema({
      slugID: { type: SimpleSchema.RegEx.Id },
      studentID: { type: SimpleSchema.RegEx.Id, optional: true },
      opportunityID: { type: SimpleSchema.RegEx.Id, optional: true },
      courseID: { type: SimpleSchema.RegEx.Id, optional: true },
      description: { type: String },
      timestamp: { type: Number },
      picture: { type: String },
    }));
  }

  /**
   * Defines a new Feed.
   * @example
   * Feed.define({ student: 'abigailkealoha',
   *                 opportunity: 'att-hackathon
   *                 course: undefined
   *                 feedType: 'verified'
   *                 timestamp: '12345465465',
   * @param { Object } description Object with keys student, opportunity, course, feedType, and timestamp.
   * @returns The newly created docID.
   */
  define({ student, opportunity, course, feedType, timestamp }) {
    let studentID;
    let opportunityID;
    let courseID;
    let picture;
    let slugID;
    if (student) {
      studentID = Users.getID(student);
    }
    if (opportunity) {
      opportunityID = Opportunities.getID(opportunity);
    }
    if (course) {
      courseID = Courses.getID(course);
    }
    let description = '';
    if (feedType === 'new') {
      if (student !== undefined) {
        description = `${Users.getFullName(studentID)} has joined RadGrad.`;
        slugID = Slugs.define({ name: `feed-${Users.findDoc(studentID).username}-new`, entityName: this.getType() });
        picture = Users.findDoc(studentID).picture;
        if (!picture) {
          picture = '/images/ICS-logo.png';
        }
      } else if (opportunity !== undefined) {
        description = `${Opportunities.findDoc(opportunityID).name} has been added to Opportunities.`;
        slugID = Slugs.define({ name: `feed-${Slugs.getDoc(Opportunities.findDoc(opportunityID).slugID).name}-new`,
          entityName: this.getType() });
        picture = '/images/radgrad_logo.png';
      } else if (course !== undefined) {
        description = `${Courses.findDoc(courseID).name} has been added to Courses.`;
        slugID = Slugs.define({ name: `${Slugs.getDoc(Courses.findDoc(courseID).slugID).name}-new`,
          entityName: this.getType() });
        picture = '/images/radgrad_logo.png';
      }
    } else if (feedType === 'verified') {
      description = `${Users.getFullName(studentID)} has been verified for
        ${Opportunities.findDoc(opportunityID).name} (${Semesters.toString(opportunity.semesterID, false)}).`;
      const username = Users.findDoc(studentID).username;
      const oppDate = Semesters.toString(opportunity.semesterID, true);
      const oppName = Slugs.findDoc((Opportunities.findDoc(opportunityID).slugID)).name;
      slugID = Slugs.define({ name: `feed-${username}-${oppName}-${oppDate}-new`, entityName: this.getType() });
      console.log(`feed-${username}-${oppName}-${oppDate}-new`);
      picture = Users.findDoc(studentID).picture;
    }
    const feedID = this._collection.insert({ slugID, studentID, opportunityID, courseID,
      description, timestamp, picture });
    Slugs.updateEntityID(slugID, feedID);
    return feedID;
  }
  getSlug(feedID) {
    this.assertDefined(feedID);
    const feedDoc = this.findDoc(feedID);
    return Slugs.findDoc(feedDoc.slugID).name;
  }
}

/**
 * Provides the singleton instance of this class to all other entities.
 */
export const Feed = new FeedCollection();

<commit_msg>Removed test statement<commit_after>import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { Users } from '/imports/api/user/UserCollection';
import { Opportunities } from '/imports/api/opportunity/OpportunityCollection';
import { Courses } from '/imports/api/course/CourseCollection';
import { Semesters } from '/imports/api/semester/SemesterCollection';
import { Slugs } from '/imports/api/slug/SlugCollection';

import BaseInstanceCollection from '/imports/api/base/BaseInstanceCollection';

/** @module Feed */

/**
 * Represents a feed instance.
 * @extends module:BaseInstance~BaseInstanceCollection
 */
class FeedCollection extends BaseInstanceCollection {

  /**
   * Creates the Feed collection.
   */
  constructor() {
    super('Feed', new SimpleSchema({
      slugID: { type: SimpleSchema.RegEx.Id },
      studentID: { type: SimpleSchema.RegEx.Id, optional: true },
      opportunityID: { type: SimpleSchema.RegEx.Id, optional: true },
      courseID: { type: SimpleSchema.RegEx.Id, optional: true },
      description: { type: String },
      timestamp: { type: Number },
      picture: { type: String },
    }));
  }

  /**
   * Defines a new Feed.
   * @example
   * Feed.define({ student: 'abigailkealoha',
   *                 opportunity: 'att-hackathon
   *                 course: undefined
   *                 feedType: 'verified'
   *                 timestamp: '12345465465',
   * @param { Object } description Object with keys student, opportunity, course, feedType, and timestamp.
   * @returns The newly created docID.
   */
  define({ student, opportunity, course, feedType, timestamp }) {
    let studentID;
    let opportunityID;
    let courseID;
    let picture;
    let slugID;
    if (student) {
      studentID = Users.getID(student);
    }
    if (opportunity) {
      opportunityID = Opportunities.getID(opportunity);
    }
    if (course) {
      courseID = Courses.getID(course);
    }
    let description = '';
    if (feedType === 'new') {
      if (student !== undefined) {
        description = `${Users.getFullName(studentID)} has joined RadGrad.`;
        slugID = Slugs.define({ name: `feed-${Users.findDoc(studentID).username}-new`, entityName: this.getType() });
        picture = Users.findDoc(studentID).picture;
        if (!picture) {
          picture = '/images/ICS-logo.png';
        }
      } else if (opportunity !== undefined) {
        description = `${Opportunities.findDoc(opportunityID).name} has been added to Opportunities.`;
        slugID = Slugs.define({ name: `feed-${Slugs.getDoc(Opportunities.findDoc(opportunityID).slugID).name}-new`,
          entityName: this.getType() });
        picture = '/images/radgrad_logo.png';
      } else if (course !== undefined) {
        description = `${Courses.findDoc(courseID).name} has been added to Courses.`;
        slugID = Slugs.define({ name: `${Slugs.getDoc(Courses.findDoc(courseID).slugID).name}-new`,
          entityName: this.getType() });
        picture = '/images/radgrad_logo.png';
      }
    } else if (feedType === 'verified') {
      description = `${Users.getFullName(studentID)} has been verified for
        ${Opportunities.findDoc(opportunityID).name} (${Semesters.toString(opportunity.semesterID, false)}).`;
      const username = Users.findDoc(studentID).username;
      const oppDate = Semesters.toString(opportunity.semesterID, true);
      const oppName = Slugs.findDoc((Opportunities.findDoc(opportunityID).slugID)).name;
      slugID = Slugs.define({ name: `feed-${username}-${oppName}-${oppDate}-new`, entityName: this.getType() });
      picture = Users.findDoc(studentID).picture;
    }
    const feedID = this._collection.insert({ slugID, studentID, opportunityID, courseID,
      description, timestamp, picture });
    Slugs.updateEntityID(slugID, feedID);
    return feedID;
  }
  getSlug(feedID) {
    this.assertDefined(feedID);
    const feedDoc = this.findDoc(feedID);
    return Slugs.findDoc(feedDoc.slugID).name;
  }
}

/**
 * Provides the singleton instance of this class to all other entities.
 */
export const Feed = new FeedCollection();

<|endoftext|>


<commit_before>// Utils.js - in api/services

"use strict";

const moment = require('moment');
const axios = require('axios');
const https = require('https');
const util = require('util');
const fs = require('fs');
const path = require('path');
const appendFile = util.promisify(fs.appendFile);
const exists = util.promisify(fs.exists);
const mkdir = util.promisify(fs.mkdir);
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

module.exports = {
    stringToSlug,
    waitForSuccessfulRequest,
    getActiveDirectoryUsers,
    log
};

function stringToSlug (str) {
    str = str.replace(/^\s+|\s+$/g, ''); // trim
    str = str.toLowerCase();

    // remove accents, swap ñ for n, etc
    const from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
    const to   = "aaaaeeeeiiiioooouuuunc------";
    for (let i=0, l=from.length ; i<l ; i++) {
        str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
    }

    str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
        .replace(/\s+/g, '-') // collapse whitespace and replace by -
        .replace(/-+/g, '-'); // collapse dashes

    return str;
}

async function waitForSuccessfulRequest(options, logMethod = false, print = true) {
    const maxAttempts = 10;

    options.timeout = options.timeout || 600000;

    if (options.httpsAgent) {
        options.httpsAgent = new https.Agent(Object.assign({},
            options.httpsAgent,
            {
                cert: await readFile(options.httpsAgent.cert),
                key: await readFile(options.httpsAgent.key)
            }));
    }

    let response = await tryRequest(options, maxAttempts, logMethod, print);

    if (response && _.has(response, 'status') && response.status === 200) {
        return response.data;
    }

    throw response;
}

async function tryRequest(options, maxAttempts, logMethod = false, print = true, attempts = 0) {
    const waitFor = 60000; // 60000 ms = 1 minute

    try {
        if (attempts != 0) {
            await new Promise(resolve => setTimeout(resolve, waitFor));
        }

        await log(`${moment()} Try to reach ${axios.getUri(options)} for the ${attempts + 1}th time ...`, logMethod, print);

        return await axios(options);
    } catch (e) {
        await log(`${moment()} Failed to reach ${axios.getUri(options)} for the ${attempts + 1}th time ...`, logMethod, print);

        if (attempts < maxAttempts) {
            return await tryRequest(options, maxAttempts, logMethod, print, attempts + 1);
        }

        if (e && e.response && e.response.status && e.response.statusText) {
            await log(`${e.response.status}: ${e.response.statusText}`, logMethod, print);
        } else {
            await log(e);
        }

        throw `Tried ${attempts} time(s), but failed to reach the API!`;
    }
}

/**
 * This function connects to the Active Directory and returns an array of users.
 **
 * @returns {Object[]}
 */
async function getActiveDirectoryUsers() {
    return await new Promise((resolve, reject) => {
        const ldap = require('ldapjs');
        const client = ldap.createClient({
            url: sails.config.scientilla.ldap.connection.url,
            tlsOptions: sails.config.scientilla.ldap.connection.tlsOptions
        });
        const result = [];

        client.bind(
            sails.config.scientilla.ldap.connection.bindDn,
            sails.config.scientilla.ldap.connection.bindCredentials,
            function (err) {
                if (err) {
                    sails.log.info(err);
                    return;
                }
                const base = sails.config.scientilla.ldap.connection.searchBase;
                const opts = {
                    filter: '(userPrincipalName=*)',
                    scope: 'sub',
                    attributes: ['userPrincipalName']
                };

                client.search(base, opts, function (err, res) {
                    if (err) {
                        reject('Error occurred while LDAP search!');
                    } else {

                        res.on('searchEntry', function (entry) {
                            result.push(entry.object);
                        });
                        res.on('error', function (err) {
                            sails.log.debug(err);
                            resolve([]);
                        });
                        res.on('end', function () {
                            resolve(result);
                        });
                    }
                });
            }
        );
    });
}

async function log(text = '', logMethod = false, print = true) {
    if (print) {
        sails.log.info(text);
    }

    if (logMethod !== false) {
        const logFile = path.join('logs', logMethod, moment().format('YYYYMMDD') + '.log');

        if (!await exists(path.join('logs', logMethod))) {
            await mkdir(path.join('logs', logMethod));
        }

        if (await exists(logFile)) {
            await appendFile(logFile, '\n' + text);
        } else {
            await writeFile(logFile, text);
        }
    }
}<commit_msg>Ignore ssl errors for development environment<commit_after>// Utils.js - in api/services

"use strict";

const moment = require('moment');
const axios = require('axios');
const https = require('https');
const util = require('util');
const fs = require('fs');
const path = require('path');
const appendFile = util.promisify(fs.appendFile);
const exists = util.promisify(fs.exists);
const mkdir = util.promisify(fs.mkdir);
const readFile = util.promisify(fs.readFile);
const writeFile = util.promisify(fs.writeFile);

module.exports = {
    stringToSlug,
    waitForSuccessfulRequest,
    getActiveDirectoryUsers,
    log
};

function stringToSlug (str) {
    str = str.replace(/^\s+|\s+$/g, ''); // trim
    str = str.toLowerCase();

    // remove accents, swap ñ for n, etc
    const from = "àáäâèéëêìíïîòóöôùúüûñç·/_,:;";
    const to   = "aaaaeeeeiiiioooouuuunc------";
    for (let i=0, l=from.length ; i<l ; i++) {
        str = str.replace(new RegExp(from.charAt(i), 'g'), to.charAt(i));
    }

    str = str.replace(/[^a-z0-9 -]/g, '') // remove invalid chars
        .replace(/\s+/g, '-') // collapse whitespace and replace by -
        .replace(/-+/g, '-'); // collapse dashes

    return str;
}

async function waitForSuccessfulRequest(options, logMethod = false, print = true) {
    const maxAttempts = 10;

    options.timeout = options.timeout || 600000;

    if (options.httpsAgent) {
        options.httpsAgent = new https.Agent(Object.assign({},
            options.httpsAgent,
            {
                cert: await readFile(options.httpsAgent.cert),
                key: await readFile(options.httpsAgent.key)
            }));
    }

    if (sails.config.environment === 'development') {
        options.httpsAgent = new https.Agent({
            rejectUnauthorized: false
        });

        options.timeout = 0;
    }

    let response = await tryRequest(options, maxAttempts, logMethod, print);

    if (response && _.has(response, 'status') && response.status === 200) {
        return response.data;
    }

    throw response;
}

async function tryRequest(options, maxAttempts, logMethod = false, print = true, attempts = 0) {
    const waitFor = 60000; // 60000 ms = 1 minute

    try {
        if (attempts != 0) {
            await new Promise(resolve => setTimeout(resolve, waitFor));
        }

        await log(`${moment()} Try to reach ${axios.getUri(options)} for the ${attempts + 1}th time ...`, logMethod, print);

        return await axios(options);
    } catch (e) {
        await log(`${moment()} Failed to reach ${axios.getUri(options)} for the ${attempts + 1}th time ...`, logMethod, print);

        if (attempts < maxAttempts) {
            return await tryRequest(options, maxAttempts, logMethod, print, attempts + 1);
        }

        if (e && e.response && e.response.status && e.response.statusText) {
            await log(`${e.response.status}: ${e.response.statusText}`, logMethod, print);
        } else {
            await log(e);
        }

        throw `Tried ${attempts} time(s), but failed to reach the API!`;
    }
}

/**
 * This function connects to the Active Directory and returns an array of users.
 **
 * @returns {Object[]}
 */
async function getActiveDirectoryUsers() {
    return await new Promise((resolve, reject) => {
        const ldap = require('ldapjs');
        const client = ldap.createClient({
            url: sails.config.scientilla.ldap.connection.url,
            tlsOptions: sails.config.scientilla.ldap.connection.tlsOptions
        });
        const result = [];

        client.bind(
            sails.config.scientilla.ldap.connection.bindDn,
            sails.config.scientilla.ldap.connection.bindCredentials,
            function (err) {
                if (err) {
                    sails.log.info(err);
                    return;
                }
                const base = sails.config.scientilla.ldap.connection.searchBase;
                const opts = {
                    filter: '(userPrincipalName=*)',
                    scope: 'sub',
                    attributes: ['userPrincipalName']
                };

                client.search(base, opts, function (err, res) {
                    if (err) {
                        reject('Error occurred while LDAP search!');
                    } else {

                        res.on('searchEntry', function (entry) {
                            result.push(entry.object);
                        });
                        res.on('error', function (err) {
                            sails.log.debug(err);
                            resolve([]);
                        });
                        res.on('end', function () {
                            resolve(result);
                        });
                    }
                });
            }
        );
    });
}

async function log(text = '', logMethod = false, print = true) {
    if (print) {
        sails.log.info(text);
    }

    if (logMethod !== false) {
        const logFile = path.join('logs', logMethod, moment().format('YYYYMMDD') + '.log');

        if (!await exists(path.join('logs', logMethod))) {
            await mkdir(path.join('logs', logMethod));
        }

        if (await exists(logFile)) {
            await appendFile(logFile, '\n' + text);
        } else {
            await writeFile(logFile, text);
        }
    }
}
<|endoftext|>