<commit_before>var _         = require('lodash');
var React     = require('react/addons');
var FormStore = require('../../../stores/FormStore');

/**
 * A mixin for simplifying some typical functionality inside Mortar's Form Components.
 * Typically only used internally to clean up Form components and reduce repeat code.
 *
 * @mixin
 */
var FormUtility = {

	/**
	 * Adds a change listener to the FormStore that fires `this._updateFieldData` on change.
	 *
	 * @private
	 * @return {null}
	 */
	_componentDidMount: function() {
		FormStore.addChangeListener(this._updateFieldData);
	},

	/**
	 * Removes the change listener.
	 *
	 * @private
	 * @return {null}
	 */
	_componentWillUnmount: function() {
		FormStore.removeChangeListener(this._updateFieldData);
	},

	/**
	 * Any time a change is registered to a form, the component will request it's data from the FormStore.
	 *
	 * So, any time a form component changes, it will automatically request it's updated data from the FormStore
	 * and bind the new value to state.  In this way, form components are responsible for re-rendering on update,
	 * and for keeping track of their own state.  This ensures that all data is kept in the FormStore, and there's
	 * no chance for data to get out of sync.
	 *
	 * @private
	 * @return {null}
	 */
	_updateFieldData: function() {
		this.setState({fieldValue: FormStore.getField(this.props.formKey, this.props.fieldKey)});
	},

	/**
	 * Finds the value of a potentially deeply nested key in an object, and returns it.
	 *
	 * @example
	 * var formResource = {user: {first_name: 'Kyle'}};
	 * _findValueByPath(formResource, 'user.first_name'); // 'Kyle'
	 * @private
	 *
	 * @param {object} object a
	 * @param {string} path a
	 *
	 * @return {value}
	 * @TODO: sunset in favor of FormStore.getValue
	 */
	_findValueByPath: function (object, path) {
		return _.get(object, path);
	},

	/**
	 * Checks to see if the help text for a component should be rendered, and handles rendering it.
	 *
	 * @private
	 *
	 * @param {string} helpText The help text to render
	 *
	 * @return {jsx}
	 * @TODO sunset
	 */
	_shouldRenderHelpBlock: function (helpText) {
		if (typeof helpText !== 'undefined') {
			return (

{this.props.helpText}

			);
		}

		return false;
	},

	/**
	 * _checkFieldIsValid
	 *
	 * @private
	 *
	 * @return {null}
	 *
	 * @TODO: this should be sunset since addition of schemas
	 */
	_checkFieldIsValid: function () {
		// If this component should be checked against a custom validation function
		if (typeof this.props.validityCheck === 'function') {
			return this.props.validityCheck(this.state.fieldValue, this.props.fieldKey);
		} else if (typeof this.props.formKey === 'string') {
			// If part of a Form
			return ! FormStore.isFieldValid(this.props.formKey, this.props.fieldKey);
		}

		return false;
	},

	/**
	 * Handles changes to form components and handles setting state with the new value
	 * as well as firing a change callback to set the field in the parent component.
	 *
	 * @public
	 *
	 * @param {event} event The event triggering the change
	 *
	 * @return {null}
	 * @TODO: sunset
	 */
	handleChange: function (event) {
		// Custom component change handler
		if (typeof this.customHandleChange !== 'undefined') {
			this.customHandleChange(event);
			return;
		}

		this.setState({
			fieldValue: event.target.value
		});

		this.props.changeCallback(this.props.fieldKey, event.target.value, this);
	},

	/**
	 * setValidationState
	 *
	 * @public
	 * @param {bool} isValid If the field is valid or not
	 * @param {function} cb  A callback to trigger
	 *
	 * @return {null}
	 */
	setValidationState: function (isValid, cb) {
		this.setState({
			isValid: isValid
		}, cb());
	}
};

module.exports = FormUtility;
<commit_msg>Updating the path to the FormStore. #8<commit_after>var _         = require('lodash');
var React     = require('react/addons');
var FormStore = require('../../../../stores/FormStore');

/**
 * A mixin for simplifying some typical functionality inside Mortar's Form Components.
 * Typically only used internally to clean up Form components and reduce repeat code.
 *
 * @mixin
 */
var FormUtility = {

	/**
	 * Adds a change listener to the FormStore that fires `this._updateFieldData` on change.
	 *
	 * @private
	 * @return {null}
	 */
	_componentDidMount: function() {
		FormStore.addChangeListener(this._updateFieldData);
	},

	/**
	 * Removes the change listener.
	 *
	 * @private
	 * @return {null}
	 */
	_componentWillUnmount: function() {
		FormStore.removeChangeListener(this._updateFieldData);
	},

	/**
	 * Any time a change is registered to a form, the component will request it's data from the FormStore.
	 *
	 * So, any time a form component changes, it will automatically request it's updated data from the FormStore
	 * and bind the new value to state.  In this way, form components are responsible for re-rendering on update,
	 * and for keeping track of their own state.  This ensures that all data is kept in the FormStore, and there's
	 * no chance for data to get out of sync.
	 *
	 * @private
	 * @return {null}
	 */
	_updateFieldData: function() {
		this.setState({fieldValue: FormStore.getField(this.props.formKey, this.props.fieldKey)});
	},

	/**
	 * Finds the value of a potentially deeply nested key in an object, and returns it.
	 *
	 * @example
	 * var formResource = {user: {first_name: 'Kyle'}};
	 * _findValueByPath(formResource, 'user.first_name'); // 'Kyle'
	 * @private
	 *
	 * @param {object} object a
	 * @param {string} path a
	 *
	 * @return {value}
	 * @TODO: sunset in favor of FormStore.getValue
	 */
	_findValueByPath: function (object, path) {
		return _.get(object, path);
	},

	/**
	 * Checks to see if the help text for a component should be rendered, and handles rendering it.
	 *
	 * @private
	 *
	 * @param {string} helpText The help text to render
	 *
	 * @return {jsx}
	 * @TODO sunset
	 */
	_shouldRenderHelpBlock: function (helpText) {
		if (typeof helpText !== 'undefined') {
			return (

{this.props.helpText}

			);
		}

		return false;
	},

	/**
	 * _checkFieldIsValid
	 *
	 * @private
	 *
	 * @return {null}
	 *
	 * @TODO: this should be sunset since addition of schemas
	 */
	_checkFieldIsValid: function () {
		// If this component should be checked against a custom validation function
		if (typeof this.props.validityCheck === 'function') {
			return this.props.validityCheck(this.state.fieldValue, this.props.fieldKey);
		} else if (typeof this.props.formKey === 'string') {
			// If part of a Form
			return ! FormStore.isFieldValid(this.props.formKey, this.props.fieldKey);
		}

		return false;
	},

	/**
	 * Handles changes to form components and handles setting state with the new value
	 * as well as firing a change callback to set the field in the parent component.
	 *
	 * @public
	 *
	 * @param {event} event The event triggering the change
	 *
	 * @return {null}
	 * @TODO: sunset
	 */
	handleChange: function (event) {
		// Custom component change handler
		if (typeof this.customHandleChange !== 'undefined') {
			this.customHandleChange(event);
			return;
		}

		this.setState({
			fieldValue: event.target.value
		});

		this.props.changeCallback(this.props.fieldKey, event.target.value, this);
	},

	/**
	 * setValidationState
	 *
	 * @public
	 * @param {bool} isValid If the field is valid or not
	 * @param {function} cb  A callback to trigger
	 *
	 * @return {null}
	 */
	setValidationState: function (isValid, cb) {
		this.setState({
			isValid: isValid
		}, cb());
	}
};

module.exports = FormUtility;
<|endoftext|>


<commit_before>'use strict';

treeherder.directive('thFilterCheckbox', [
    'thResultStatusInfo',
    function (thResultStatusInfo) {

    return {
        restrict: "E",
        link: function(scope, element, attrs) {
            scope.checkClass = thResultStatusInfo(scope.filterName).btnClass + "-count-classified";
        },
        templateUrl: 'partials/thFilterCheckbox.html'
    };
}]);

treeherder.directive('thWatchedRepo', [
    'ThLog',
    function (ThLog) {

    var $log = new ThLog("thWatchedRepo");

    var statusInfo = {
        "open": {
            icon: "fa-circle-o",
            color: "treeOpen"
        },
        "approval required": {
            icon: "fa-lock",
            color: "treeApproval"
        },
        "closed": {
            icon: "fa-times-circle",
            color: "treeClosed"
        },
        "unavailable": {
            icon: "fa-chain-broken",
            color: "treeUnavailable"
        }
    };

    return {
        restrict: "E",
        link: function(scope, element, attrs) {

            scope.updateCount = function() {
                scope.adjustedUnclassifiedFailureCount = scope.getUnclassifiedFailureCount(
                    scope.name);
            };

            scope.updateTitleText = function() {
                scope.titleText = scope.repoData.treeStatus.status;

                if (scope.adjustedUnclassifiedFailureCount > 0) {
                    scope.titleText = scope.titleText + ' - ' +
                        scope.adjustedUnclassifiedFailureCount +
                        " unclassified failures in past week";
                }
                if (scope.repoData.treeStatus.message_of_the_day) {
                    scope.titleText = scope.titleText + ' - ' +
                        scope.repoData.treeStatus.message_of_the_day;
                }
            };

            scope.$watch('repoData', function(newVal) {
                if (newVal.treeStatus) {
                    $log.debug("updated treeStatus", newVal.treeStatus.status);
                    scope.statusIcon = statusInfo[newVal.treeStatus.status].icon;
                    scope.statusColor = statusInfo[newVal.treeStatus.status].color;
                    scope.updateCount();
                    scope.updateTitleText();
                }
            }, true);

            scope.$watch('isSkippingExclusionProfiles()', function(newVal) {
                scope.updateCount();
                scope.updateTitleText();
            });

        },
        templateUrl: 'partials/thWatchedRepo.html'
    };
}]);

treeherder.directive('thRepoDropDown', [
    'ThLog', 'ThRepositoryModel',
    function (ThLog, ThRepositoryModel) {

    var $log = new ThLog("thRepoDropDown");

    return {
        restrict: "E",
        replace: true,
        link: function(scope, element, attrs) {

            scope.name = attrs.name;
            var repo_obj = ThRepositoryModel.getRepo(attrs.name);
            scope.pushlog = repo_obj.url +"/pushloghtml";

            scope.$watch('repoData.treeStatus', function(newVal) {
                if (newVal) {
                    $log.debug("updated treeStatus", repo_obj, newVal);
                    scope.reason = newVal.reason;
                    scope.message_of_the_day = newVal.message_of_the_day;
                }
            }, true);

        },
        templateUrl: 'partials/thRepoDropDown.html'
    };
}]);
<commit_msg>needed a null check<commit_after>'use strict';

treeherder.directive('thFilterCheckbox', [
    'thResultStatusInfo',
    function (thResultStatusInfo) {

    return {
        restrict: "E",
        link: function(scope, element, attrs) {
            scope.checkClass = thResultStatusInfo(scope.filterName).btnClass + "-count-classified";
        },
        templateUrl: 'partials/thFilterCheckbox.html'
    };
}]);

treeherder.directive('thWatchedRepo', [
    'ThLog',
    function (ThLog) {

    var $log = new ThLog("thWatchedRepo");

    var statusInfo = {
        "open": {
            icon: "fa-circle-o",
            color: "treeOpen"
        },
        "approval required": {
            icon: "fa-lock",
            color: "treeApproval"
        },
        "closed": {
            icon: "fa-times-circle",
            color: "treeClosed"
        },
        "unavailable": {
            icon: "fa-chain-broken",
            color: "treeUnavailable"
        }
    };

    return {
        restrict: "E",
        link: function(scope, element, attrs) {

            scope.updateCount = function() {
                scope.adjustedUnclassifiedFailureCount = scope.getUnclassifiedFailureCount(
                    scope.name);
            };

            scope.updateTitleText = function() {
                if (scope.repoData.treeStatus) {
                    scope.titleText = scope.repoData.treeStatus.status;

                    if (scope.adjustedUnclassifiedFailureCount > 0) {
                        scope.titleText = scope.titleText + ' - ' +
                            scope.adjustedUnclassifiedFailureCount +
                            " unclassified failures in past week";
                    }
                    if (scope.repoData.treeStatus.message_of_the_day) {
                        scope.titleText = scope.titleText + ' - ' +
                            scope.repoData.treeStatus.message_of_the_day;
                    }
                }
            };

            scope.$watch('repoData', function(newVal) {
                if (newVal.treeStatus) {
                    $log.debug("updated treeStatus", newVal.treeStatus.status);
                    scope.statusIcon = statusInfo[newVal.treeStatus.status].icon;
                    scope.statusColor = statusInfo[newVal.treeStatus.status].color;
                    scope.updateCount();
                    scope.updateTitleText();
                }
            }, true);

            scope.$watch('isSkippingExclusionProfiles()', function(newVal) {
                scope.updateCount();
                scope.updateTitleText();
            });

        },
        templateUrl: 'partials/thWatchedRepo.html'
    };
}]);

treeherder.directive('thRepoDropDown', [
    'ThLog', 'ThRepositoryModel',
    function (ThLog, ThRepositoryModel) {

    var $log = new ThLog("thRepoDropDown");

    return {
        restrict: "E",
        replace: true,
        link: function(scope, element, attrs) {

            scope.name = attrs.name;
            var repo_obj = ThRepositoryModel.getRepo(attrs.name);
            scope.pushlog = repo_obj.url +"/pushloghtml";

            scope.$watch('repoData.treeStatus', function(newVal) {
                if (newVal) {
                    $log.debug("updated treeStatus", repo_obj, newVal);
                    scope.reason = newVal.reason;
                    scope.message_of_the_day = newVal.message_of_the_day;
                }
            }, true);

        },
        templateUrl: 'partials/thRepoDropDown.html'
    };
}]);
<|endoftext|>


<commit_before>/*
 * Copyright © 2016-2019 The Thingsboard Authors
 *
 * 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.
 */
export default angular.module('thingsboard.api.alarm', [])
    .factory('alarmService', AlarmService)
    .name;

/*@ngInject*/
function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) {

    var alarmSourceListeners = {};

    var simulatedAlarm = {
        createdTime: (new Date).getTime(),
        startTs: (new Date).getTime(),
        endTs: 0,
        ackTs: 0,
        clearTs: 0,
        originatorName: 'Simulated',
        originator: {
            entityType: "DEVICE",
            id: "1"
        },
        type: 'TEMPERATURE',
        severity: "MAJOR",
        status: types.alarmStatus.activeUnack,
        details: {
            message: "Temperature is high!"
        }
    };

    var service = {
        getAlarm: getAlarm,
        getAlarmInfo: getAlarmInfo,
        saveAlarm: saveAlarm,
        ackAlarm: ackAlarm,
        clearAlarm: clearAlarm,
        getAlarms: getAlarms,
        getHighestAlarmSeverity: getHighestAlarmSeverity,
        pollAlarms: pollAlarms,
        cancelPollAlarms: cancelPollAlarms,
        subscribeForAlarms: subscribeForAlarms,
        unsubscribeFromAlarms: unsubscribeFromAlarms
    }

    return service;

    function getAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId;
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getAlarmInfo(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/info/' + alarmId;
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function saveAlarm(alarm, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, alarm, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function ackAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId + '/ack';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, null, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function clearAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId + '/clear';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, null, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getAlarms(entityType, entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, ascOrder, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit;

        if (angular.isDefined(pageLink.startTime) && pageLink.startTime != null) {
            url += '&startTime=' + pageLink.startTime;
        }
        if (angular.isDefined(pageLink.endTime) && pageLink.endTime != null) {
            url += '&endTime=' + pageLink.endTime;
        }
        if (angular.isDefined(pageLink.idOffset) && pageLink.idOffset != null) {
            url += '&offset=' + pageLink.idOffset;
        }
        if (alarmSearchStatus) {
            url += '&searchStatus=' + alarmSearchStatus;
        }
        if (alarmStatus) {
            url += '&status=' + alarmStatus;
        }
        if (fetchOriginator) {
            url += '&fetchOriginator=' + ((fetchOriginator===true) ? 'true' : 'false');
        }
        if (angular.isDefined(ascOrder) && ascOrder != null) {
            url += '&ascOrder=' + (ascOrder ? 'true' : 'false');
        }

        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getHighestAlarmSeverity(entityType, entityId, alarmSearchStatus, alarmStatus, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/highestSeverity/' + entityType + '/' + entityId;

        if (alarmSearchStatus) {
            url += '?searchStatus=' + alarmSearchStatus;
        } else if (alarmStatus) {
            url += '?status=' + alarmStatus;
        }
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad, alarmsList) {
        getAlarms(alarmsQuery.entityType, alarmsQuery.entityId,
            pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus,
            alarmsQuery.fetchOriginator, false, {ignoreLoading: true}).then(
            function success(alarms) {
                if (!alarmsList) {
                    alarmsList = [];
                }
                alarmsList = alarmsList.concat(alarms.data);
                if (angular.isDefined(leftToLoad)) {
                    leftToLoad -= pageLink.limit;
                    if (leftToLoad === 0) {
                        alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']);
                        deferred.resolve(alarmsList);
                        return;
                    }
                    if (leftToLoad < pageLink.limit) {
                        alarms.nextPageLink.limit = leftToLoad;
                    }
                }
                if (alarms.hasNext && !alarmsQuery.limit) {
                    fetchAlarms(alarmsQuery, alarms.nextPageLink, deferred, leftToLoad, alarmsList);
                } else {
                    alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']);
                    deferred.resolve(alarmsList);
                }
            },
            function fail() {
                deferred.reject();
            }
        );
    }

    function getAlarmsByQuery(alarmsQuery) {
        var deferred = $q.defer();
        var time = Date.now();
        var pageLink;
        var leftToLoad;
        if (alarmsQuery.limit) {
            pageLink = {
                limit: alarmsQuery.limit
            };
        } else if (alarmsQuery.interval) {
            pageLink = {
                limit: alarmsQuery.alarmsFetchSize || 100,
                startTime: time - alarmsQuery.interval
            };
        } else if (alarmsQuery.startTime) {
            pageLink = {
                limit: alarmsQuery.alarmsFetchSize || 100,
                startTime: Math.round(alarmsQuery.startTime)
            };
            if (alarmsQuery.endTime) {
                pageLink.endTime = Math.round(alarmsQuery.endTime);
            }
        }

        if (angular.isDefined(alarmsQuery.alarmsMaxCountLoad) && alarmsQuery.alarmsMaxCountLoad !== 0) {
            leftToLoad = alarmsQuery.alarmsMaxCountLoad;
            if (leftToLoad < pageLink.limit) {
                pageLink.limit = leftToLoad;
            }
        }

        fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad);
        return deferred.promise;
    }

    function onPollAlarms(alarmsQuery) {
        getAlarmsByQuery(alarmsQuery).then(
            function success(alarms) {
                alarmsQuery.onAlarms(alarms);
            },
            function fail() {}
        );
    }

    function pollAlarms(entityType, entityId, alarmStatus, interval, limit, pollingInterval, onAlarms) {
        var alarmsQuery = {
            entityType: entityType,
            entityId: entityId,
            alarmSearchStatus: null,
            alarmStatus: alarmStatus,
            fetchOriginator: false,
            interval: interval,
            limit: limit,
            onAlarms: onAlarms
        };
        onPollAlarms(alarmsQuery);
        return $interval(onPollAlarms, pollingInterval, 0, false, alarmsQuery);
    }

    function cancelPollAlarms(pollPromise) {
        if (angular.isDefined(pollPromise)) {
            $interval.cancel(pollPromise);
        }
    }

    function subscribeForAlarms(alarmSourceListener) {
        alarmSourceListener.id = utils.guid();
        alarmSourceListeners[alarmSourceListener.id] = alarmSourceListener;
        var alarmSource = alarmSourceListener.alarmSource;
        if (alarmSource.type == types.datasourceType.function) {
            $timeout(function() {
                alarmSourceListener.alarmsUpdated([simulatedAlarm], false);
            });
        } else if (alarmSource.entityType && alarmSource.entityId) {
            var pollingInterval = alarmSourceListener.alarmsPollingInterval;
            alarmSourceListener.alarmsQuery = {
                entityType: alarmSource.entityType,
                entityId: alarmSource.entityId,
                alarmSearchStatus: alarmSourceListener.alarmSearchStatus,
                alarmStatus: null,
                alarmsMaxCountLoad: alarmSourceListener.alarmsMaxCountLoad,
                alarmsFetchSize: alarmSourceListener.alarmsFetchSize
            };
            var originatorKeys = $filter('filter')(alarmSource.dataKeys, {name: 'originator'});
            if (originatorKeys && originatorKeys.length) {
                alarmSourceListener.alarmsQuery.fetchOriginator = true;
            }
            var subscriptionTimewindow = alarmSourceListener.subscriptionTimewindow;
            if (subscriptionTimewindow.realtimeWindowMs) {
                alarmSourceListener.alarmsQuery.startTime = subscriptionTimewindow.startTs;
            } else {
                alarmSourceListener.alarmsQuery.startTime = subscriptionTimewindow.fixedWindow.startTimeMs;
                alarmSourceListener.alarmsQuery.endTime = subscriptionTimewindow.fixedWindow.endTimeMs;
            }
            alarmSourceListener.alarmsQuery.onAlarms = function(alarms) {
                if (subscriptionTimewindow.realtimeWindowMs) {
                    var now = Date.now();
                    if (alarmSourceListener.lastUpdateTs) {
                        var interval = now - alarmSourceListener.lastUpdateTs;
                        alarmSourceListener.alarmsQuery.startTime += interval;
                    }
                    alarmSourceListener.lastUpdateTs = now;
                }
                alarmSourceListener.alarmsUpdated(alarms, false);
            }
            onPollAlarms(alarmSourceListener.alarmsQuery);
            alarmSourceListener.pollPromise = $interval(onPollAlarms, pollingInterval,
                0, false, alarmSourceListener.alarmsQuery);
        }

    }

    function unsubscribeFromAlarms(alarmSourceListener) {
        if (alarmSourceListener && alarmSourceListener.id) {
            if (alarmSourceListener.pollPromise) {
                $interval.cancel(alarmSourceListener.pollPromise);
                alarmSourceListener.pollPromise = null;
            }
            delete alarmSourceListeners[alarmSourceListener.id];
        }
    }
}
<commit_msg>added delete alarm to ui service (#2266)<commit_after>/*
 * Copyright © 2016-2019 The Thingsboard Authors
 *
 * 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.
 */
export default angular.module('thingsboard.api.alarm', [])
    .factory('alarmService', AlarmService)
    .name;

/*@ngInject*/
function AlarmService($http, $q, $interval, $filter, $timeout, utils, types) {

    var alarmSourceListeners = {};

    var simulatedAlarm = {
        createdTime: (new Date).getTime(),
        startTs: (new Date).getTime(),
        endTs: 0,
        ackTs: 0,
        clearTs: 0,
        originatorName: 'Simulated',
        originator: {
            entityType: "DEVICE",
            id: "1"
        },
        type: 'TEMPERATURE',
        severity: "MAJOR",
        status: types.alarmStatus.activeUnack,
        details: {
            message: "Temperature is high!"
        }
    };

    var service = {
        getAlarm: getAlarm,
        getAlarmInfo: getAlarmInfo,
        saveAlarm: saveAlarm,
        ackAlarm: ackAlarm,
        clearAlarm: clearAlarm,
        deleteAlarm: deleteAlarm,
        getAlarms: getAlarms,
        getHighestAlarmSeverity: getHighestAlarmSeverity,
        pollAlarms: pollAlarms,
        cancelPollAlarms: cancelPollAlarms,
        subscribeForAlarms: subscribeForAlarms,
        unsubscribeFromAlarms: unsubscribeFromAlarms
    }

    return service;

    function getAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId;
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getAlarmInfo(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/info/' + alarmId;
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function saveAlarm(alarm, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, alarm, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function ackAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId + '/ack';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, null, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function clearAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId + '/clear';
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.post(url, null, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function deleteAlarm(alarmId, ignoreErrors, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + alarmId;
        if (!config) {
            config = {};
        }
        config = Object.assign(config, { ignoreErrors: ignoreErrors });
        $http.delete(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getAlarms(entityType, entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, ascOrder, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/' + entityType + '/' + entityId + '?limit=' + pageLink.limit;

        if (angular.isDefined(pageLink.startTime) && pageLink.startTime != null) {
            url += '&startTime=' + pageLink.startTime;
        }
        if (angular.isDefined(pageLink.endTime) && pageLink.endTime != null) {
            url += '&endTime=' + pageLink.endTime;
        }
        if (angular.isDefined(pageLink.idOffset) && pageLink.idOffset != null) {
            url += '&offset=' + pageLink.idOffset;
        }
        if (alarmSearchStatus) {
            url += '&searchStatus=' + alarmSearchStatus;
        }
        if (alarmStatus) {
            url += '&status=' + alarmStatus;
        }
        if (fetchOriginator) {
            url += '&fetchOriginator=' + ((fetchOriginator===true) ? 'true' : 'false');
        }
        if (angular.isDefined(ascOrder) && ascOrder != null) {
            url += '&ascOrder=' + (ascOrder ? 'true' : 'false');
        }

        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function getHighestAlarmSeverity(entityType, entityId, alarmSearchStatus, alarmStatus, config) {
        var deferred = $q.defer();
        var url = '/api/alarm/highestSeverity/' + entityType + '/' + entityId;

        if (alarmSearchStatus) {
            url += '?searchStatus=' + alarmSearchStatus;
        } else if (alarmStatus) {
            url += '?status=' + alarmStatus;
        }
        $http.get(url, config).then(function success(response) {
            deferred.resolve(response.data);
        }, function fail() {
            deferred.reject();
        });
        return deferred.promise;
    }

    function fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad, alarmsList) {
        getAlarms(alarmsQuery.entityType, alarmsQuery.entityId,
            pageLink, alarmsQuery.alarmSearchStatus, alarmsQuery.alarmStatus,
            alarmsQuery.fetchOriginator, false, {ignoreLoading: true}).then(
            function success(alarms) {
                if (!alarmsList) {
                    alarmsList = [];
                }
                alarmsList = alarmsList.concat(alarms.data);
                if (angular.isDefined(leftToLoad)) {
                    leftToLoad -= pageLink.limit;
                    if (leftToLoad === 0) {
                        alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']);
                        deferred.resolve(alarmsList);
                        return;
                    }
                    if (leftToLoad < pageLink.limit) {
                        alarms.nextPageLink.limit = leftToLoad;
                    }
                }
                if (alarms.hasNext && !alarmsQuery.limit) {
                    fetchAlarms(alarmsQuery, alarms.nextPageLink, deferred, leftToLoad, alarmsList);
                } else {
                    alarmsList = $filter('orderBy')(alarmsList, ['-createdTime']);
                    deferred.resolve(alarmsList);
                }
            },
            function fail() {
                deferred.reject();
            }
        );
    }

    function getAlarmsByQuery(alarmsQuery) {
        var deferred = $q.defer();
        var time = Date.now();
        var pageLink;
        var leftToLoad;
        if (alarmsQuery.limit) {
            pageLink = {
                limit: alarmsQuery.limit
            };
        } else if (alarmsQuery.interval) {
            pageLink = {
                limit: alarmsQuery.alarmsFetchSize || 100,
                startTime: time - alarmsQuery.interval
            };
        } else if (alarmsQuery.startTime) {
            pageLink = {
                limit: alarmsQuery.alarmsFetchSize || 100,
                startTime: Math.round(alarmsQuery.startTime)
            };
            if (alarmsQuery.endTime) {
                pageLink.endTime = Math.round(alarmsQuery.endTime);
            }
        }

        if (angular.isDefined(alarmsQuery.alarmsMaxCountLoad) && alarmsQuery.alarmsMaxCountLoad !== 0) {
            leftToLoad = alarmsQuery.alarmsMaxCountLoad;
            if (leftToLoad < pageLink.limit) {
                pageLink.limit = leftToLoad;
            }
        }

        fetchAlarms(alarmsQuery, pageLink, deferred, leftToLoad);
        return deferred.promise;
    }

    function onPollAlarms(alarmsQuery) {
        getAlarmsByQuery(alarmsQuery).then(
            function success(alarms) {
                alarmsQuery.onAlarms(alarms);
            },
            function fail() {}
        );
    }

    function pollAlarms(entityType, entityId, alarmStatus, interval, limit, pollingInterval, onAlarms) {
        var alarmsQuery = {
            entityType: entityType,
            entityId: entityId,
            alarmSearchStatus: null,
            alarmStatus: alarmStatus,
            fetchOriginator: false,
            interval: interval,
            limit: limit,
            onAlarms: onAlarms
        };
        onPollAlarms(alarmsQuery);
        return $interval(onPollAlarms, pollingInterval, 0, false, alarmsQuery);
    }

    function cancelPollAlarms(pollPromise) {
        if (angular.isDefined(pollPromise)) {
            $interval.cancel(pollPromise);
        }
    }

    function subscribeForAlarms(alarmSourceListener) {
        alarmSourceListener.id = utils.guid();
        alarmSourceListeners[alarmSourceListener.id] = alarmSourceListener;
        var alarmSource = alarmSourceListener.alarmSource;
        if (alarmSource.type == types.datasourceType.function) {
            $timeout(function() {
                alarmSourceListener.alarmsUpdated([simulatedAlarm], false);
            });
        } else if (alarmSource.entityType && alarmSource.entityId) {
            var pollingInterval = alarmSourceListener.alarmsPollingInterval;
            alarmSourceListener.alarmsQuery = {
                entityType: alarmSource.entityType,
                entityId: alarmSource.entityId,
                alarmSearchStatus: alarmSourceListener.alarmSearchStatus,
                alarmStatus: null,
                alarmsMaxCountLoad: alarmSourceListener.alarmsMaxCountLoad,
                alarmsFetchSize: alarmSourceListener.alarmsFetchSize
            };
            var originatorKeys = $filter('filter')(alarmSource.dataKeys, {name: 'originator'});
            if (originatorKeys && originatorKeys.length) {
                alarmSourceListener.alarmsQuery.fetchOriginator = true;
            }
            var subscriptionTimewindow = alarmSourceListener.subscriptionTimewindow;
            if (subscriptionTimewindow.realtimeWindowMs) {
                alarmSourceListener.alarmsQuery.startTime = subscriptionTimewindow.startTs;
            } else {
                alarmSourceListener.alarmsQuery.startTime = subscriptionTimewindow.fixedWindow.startTimeMs;
                alarmSourceListener.alarmsQuery.endTime = subscriptionTimewindow.fixedWindow.endTimeMs;
            }
            alarmSourceListener.alarmsQuery.onAlarms = function(alarms) {
                if (subscriptionTimewindow.realtimeWindowMs) {
                    var now = Date.now();
                    if (alarmSourceListener.lastUpdateTs) {
                        var interval = now - alarmSourceListener.lastUpdateTs;
                        alarmSourceListener.alarmsQuery.startTime += interval;
                    }
                    alarmSourceListener.lastUpdateTs = now;
                }
                alarmSourceListener.alarmsUpdated(alarms, false);
            }
            onPollAlarms(alarmSourceListener.alarmsQuery);
            alarmSourceListener.pollPromise = $interval(onPollAlarms, pollingInterval,
                0, false, alarmSourceListener.alarmsQuery);
        }

    }

    function unsubscribeFromAlarms(alarmSourceListener) {
        if (alarmSourceListener && alarmSourceListener.id) {
            if (alarmSourceListener.pollPromise) {
                $interval.cancel(alarmSourceListener.pollPromise);
                alarmSourceListener.pollPromise = null;
            }
            delete alarmSourceListeners[alarmSourceListener.id];
        }
    }
}
<|endoftext|>


<commit_before>import defineReactivePlugin from '../utils/private/define-reactive-plugin.js'
import { changeGlobalNodesTarget } from '../utils/private/global-nodes.js'

const prefixes = {}

function getFullscreenElement () {
  return (
    document.fullscreenElement
    || document.mozFullScreenElement
    || document.webkitFullscreenElement
    || document.msFullscreenElement
  )
}

// needed for consistency across browsers
function promisify (target, fn) {
  try {
    const res = target[ fn ]()
    return res === void 0
      ? Promise.resolve()
      : res
  }
  catch (err) {
    return Promise.reject(err)
  }
}

const Plugin = defineReactivePlugin({
  isActive: false,
  activeEl: null
}, {
  isCapable: false,

  request (target) {
    if (Plugin.isCapable === true && Plugin.isActive === false) {
      const el = target || document.documentElement
      return promisify(el, prefixes.request)
    }

    return Plugin.__getErr()
  },

  exit () {
    return Plugin.isCapable === true && Plugin.isActive === true
      ? promisify(document, prefixes.exit)
      : Plugin.__getErr()
  },

  toggle (target) {
    return Plugin.isActive === true
      ? Plugin.exit()
      : Plugin.request(target)
  },

  install ({ $q }) {
    $q.fullscreen = this
  }
})

if (__QUASAR_SSR_SERVER__ !== true) {
  function init () {
    prefixes.request = [
      'requestFullscreen',
      'msRequestFullscreen', 'mozRequestFullScreen', 'webkitRequestFullscreen'
    ].find(request => document.documentElement[ request ] !== void 0)

    Plugin.isCapable = prefixes.request !== void 0

    if (Plugin.isCapable === false) {
      // it means the browser does NOT support it
      Plugin.__getErr = () => Promise.reject('Not capable')
      return
    }

    Plugin.__getErr = () => Promise.resolve()

    prefixes.exit = [
      'exitFullscreen',
      'msExitFullscreen', 'mozCancelFullScreen', 'webkitExitFullscreen'
    ].find(exit => document[ exit ])

    Plugin.isActive = !!getFullscreenElement()

    ;[
      'onfullscreenchange',
      'onmsfullscreenchange', 'onwebkitfullscreenchange'
    ].forEach(evt => {
      document[ evt ] = () => {
        Plugin.isActive = Plugin.isActive === false

        if (Plugin.isActive === false) {
          Plugin.activeEl = null
          changeGlobalNodesTarget(document.body)
        }
        else {
          Plugin.activeEl = getFullscreenElement()
          changeGlobalNodesTarget(
            Plugin.activeEl === document.documentElement
              ? document.body
              : Plugin.activeEl
          )
        }
      }
    })
  }

  init()
}

export default Plugin
<commit_msg>feat(AppFullscreen): request() now accepts another node while in fullscreen already<commit_after>import defineReactivePlugin from '../utils/private/define-reactive-plugin.js'
import { changeGlobalNodesTarget } from '../utils/private/global-nodes.js'

const prefixes = {}

function assignFn (fn) {
  Object.assign(Plugin, {
    request: fn,
    exit: fn,
    toggle: fn
  })
}

function getFullscreenElement () {
  return (
    document.fullscreenElement
    || document.mozFullScreenElement
    || document.webkitFullscreenElement
    || document.msFullscreenElement
    || null
  )
}

function updateEl () {
  const newEl = Plugin.activeEl = Plugin.isActive === false
    ? null
    : getFullscreenElement()

  changeGlobalNodesTarget(
    newEl === null || newEl === document.documentElement
      ? document.body
      : newEl
  )
}

function togglePluginState () {
  Plugin.isActive = Plugin.isActive === false
  updateEl()
}

// needed for consistency across browsers
function promisify (target, fn) {
  try {
    const res = target[ fn ]()
    return res === void 0
      ? Promise.resolve()
      : res
  }
  catch (err) {
    return Promise.reject(err)
  }
}

const Plugin = defineReactivePlugin({
  isActive: false,
  activeEl: null
}, {
  isCapable: false,

  install ({ $q }) {
    $q.fullscreen = this
  }
})

if (__QUASAR_SSR_SERVER__ === true) {
  assignFn(() => Promise.resolve())
}
else {
  prefixes.request = [
    'requestFullscreen',
    'msRequestFullscreen', 'mozRequestFullScreen', 'webkitRequestFullscreen'
  ].find(request => document.documentElement[ request ] !== void 0)

  Plugin.isCapable = prefixes.request !== void 0

  if (Plugin.isCapable === false) {
    // it means the browser does NOT support it
    assignFn(() => Promise.reject('Not capable'))
  }
  else {
    Object.assign(Plugin, {
      request (target) {
        const el = target || document.documentElement
        const { activeEl } = Plugin

        if (el === activeEl) {
          return Promise.resolve()
        }

        const queue = activeEl !== null && el.contains(activeEl) === true
          ? Plugin.exit()
          : Promise.resolve()

        return queue.finally(() => promisify(el, prefixes.request))
      },

      exit () {
        return Plugin.isActive === true
          ? promisify(document, prefixes.exit)
          : Promise.resolve()
      },

      toggle (target) {
        return Plugin.isActive === true
          ? Plugin.exit()
          : Plugin.request(target)
      }
    })

    prefixes.exit = [
      'exitFullscreen',
      'msExitFullscreen', 'mozCancelFullScreen', 'webkitExitFullscreen'
    ].find(exit => document[ exit ])

    Plugin.isActive = Boolean(getFullscreenElement())
    Plugin.isActive === true && updateEl()

    ;[
      'onfullscreenchange',
      'onmsfullscreenchange', 'onwebkitfullscreenchange'
    ].forEach(evt => {
      document[ evt ] = togglePluginState
    })
  }
}

export default Plugin
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn;

var MongoURI = require('mongo-uri');
var Promise = require('bluebird');
var fs = require('fs');
var os = require('os');
var path = require('path');

/**
 * @param {Object} opts
 * @param {String} opts.collection
 * @param {String} [opts.uri]
 * @param {Array<String>} [opts.ports]
 * @param {Array<String>} [opts.hosts]
 * @param {String} [opts.username]
 * @param {String} [opts.password]
 * @param {String} [opts.database]
 * @returns {Array}
 */
function createDumpArgs(opts) {
  var args = [];
  var _hostInfo = opts.uri ? MongoURI.parse(opts.uri) : opts;
  // We assume we connect to the first instance
  var host = _hostInfo.ports[0] ? _hostInfo.hosts[0] + ':' + _hostInfo.ports[0] : _hostInfo.hosts[0];

  if (host) {
    args.push('-h', host);
  }
  if (_hostInfo.username) {
    args.push('-u', _hostInfo.username);
  }
  if (_hostInfo.password) {
    args.push('-p', _hostInfo.password);
  }
  args.push('-d', _hostInfo.database);
  args.push('-c', opts.collection);
  // Output (stdout)
  args.push('-o', '-');

  return args;
}

/**
 * @param opts
 * @param {string} opts.uri
 * @param {string} opts.collection
 * @param {Function} [_log]
 * @returns {bluebird}
 */
module.exports = function spawnMongodump(opts, _log) {
  var log = _log === undefined ? console.log : _log;
  return new Promise(function(resolve, reject) {
    var args = createDumpArgs(opts);
    var fileName = opts.collection + '.bson';
    var output = path.join(os.tmpDir(), fileName);
    var mongodump = spawn('mongodump', args);

    mongodump.stdout.pipe(fs.createWriteStream(output));
    if (typeof log === 'function') {
      mongodump.stderr.on('data', function(data) {
        log(data.toString('ascii'), opts.collection);
      });
    }
    mongodump.on('error', reject);
    return mongodump.stdout.on('end', function() {
      return resolve({
        name: fileName,
        path: output
      });
    });
  });
};
<commit_msg>Coding style<commit_after>var spawn = require('child_process').spawn;

var MongoURI = require('mongo-uri');
var Promise = require('bluebird');
var fs = require('fs');
var os = require('os');
var path = require('path');

/**
 * @param {Object} opts
 * @param {String} opts.collection
 * @param {String} [opts.uri]
 * @param {Array<String>} [opts.ports]
 * @param {Array<String>} [opts.hosts]
 * @param {String} [opts.username]
 * @param {String} [opts.password]
 * @param {String} [opts.database]
 * @returns {Array}
 */
function createDumpArgs(opts) {
  var args = [];
  var _hostInfo = opts.uri ? MongoURI.parse(opts.uri) : opts;
  // We assume we connect to the first instance
  var host = _hostInfo.ports[0] ? _hostInfo.hosts[0] + ':' + _hostInfo.ports[0] : _hostInfo.hosts[0];

  if (host) {
    args.push('-h', host);
  }
  if (_hostInfo.username) {
    args.push('-u', _hostInfo.username);
  }
  if (_hostInfo.password) {
    args.push('-p', _hostInfo.password);
  }
  args.push('-d', _hostInfo.database);
  args.push('-c', opts.collection);
  // Output (stdout)
  args.push('-o', '-');

  return args;
}

/**
 * @param opts
 * @param {string} opts.uri
 * @param {string} opts.collection
 * @param {Function} [_log]
 * @returns {bluebird}
 */
module.exports = function spawnMongodump(opts, _log) {
  var log = _log === undefined ? console.log : _log;

  return new Promise(function(resolve, reject) {
    var args = createDumpArgs(opts);
    var fileName = opts.collection + '.bson';
    var output = path.join(os.tmpDir(), fileName);
    var mongodump = spawn('mongodump', args);

    mongodump.stdout.pipe(fs.createWriteStream(output));
    if (typeof log === 'function') {
      mongodump.stderr.on('data', function(data) {
        log(data.toString('ascii'), opts.collection);
      });
    }
    mongodump.on('error', reject);
    return mongodump.stdout.on('end', function() {
      return resolve({
        name: fileName,
        path: output
      });
    });
  });
};
<|endoftext|>


<commit_before>import { WebClient } from '@slack/client';

import {
  computeMessageRating,
  computeUserPsychoPass,
  computeChannelPsychoPass,
  NUM_USER_MESSAGES,
  NUM_CHANNEL_MESSAGES,
} from './psychoPass';
import Leaderboard from './leaderboard/Leaderboard';

/**
 * Class responsible for processing input and maintaing the application state.
 * Produces a response to be sent to the client when appropriate.
 */
export default class {
  /**
   * Initialize data store and Slack web client.
   *
   * @param {WebClient} web A WebClient instance.
   * @param {Map<string, object>} userData Map from user id to an object
   * containing user data.
   * @param {Map<string, object>} channelData Map from channel id to an object
   * containing channel data.
   */
  constructor(web, userData, channelData) {
    this.store = {
      users: userData,
      channels: channelData,
      leaderboards: { users: new Leaderboard(), channels: new Leaderboard() },
    };
    this.web = web;

    this.initializeUserLeaderboard();
    this.initializeChannelLeaderboard();
  }

  /**
   * Create an instance of the Sibyl class.
   *
   * @public
   * @param {string} token The Slack API token.
   * @return {Promise<Sibyl>} Instance of Sibyl class.
   */
  static createSibyl(token) {
    const web = new WebClient(token);
    const userData = this.getInitialUserData(web);
    const channelData = this.getInitialChannelData(web);
    const sibyl = Promise.all([userData, channelData]).then(
      ([userData, channelData]) => {
        return new this(web, userData, channelData);
      }
    );

    return sibyl;
  }

  /**
   * Fetch initial user data.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @return {Promise<Map<string, object>>} Map from user id to user data
   * object.
   */
  static getInitialUserData(web) {
    return web.users.list().then(({ members }) => {
      const map = new Map();
      const promises = [];

      for (const { id, name, real_name } of members) {
        const promise = this.compileUserData(web, name, real_name).then(
          (userData) => {
            map.set(id, userData);
          }
        );

        promises.push(promise);
      }

      return Promise.all(promises).then(() => map);
    });
  }

  /**
   * Compile data for the given user.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} username The username by which to identify the user.
   * @param {string} name The name of the user.
   * @return {Promise<object>} Data related to the user.
   */
  static compileUserData(web, username, name) {
    return this.fetchUserMessages(web, username).then((messages) => {
      const messageInfo = messages.map(({ message, channel, timestamp }) => {
        const rating = computeMessageRating(message);
        return { rating, channel, timestamp };
      });
      const ratings = messageInfo.map(({ rating }) => rating);
      const psychoPass = computeUserPsychoPass(ratings);

      return { username, name, psychoPass, messageInfo };
    });
  }

  /**
   * Fetch initial channel data.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @return {Promise<Map<string, object>>} Map from channel id to channel data
   * object.
   */
  static getInitialChannelData(web) {
    return web.channels.list({ exclude_archived: 1 }).then(({ channels }) => {
      const map = new Map();
      const promises = [];

      for (const { id, name } of channels) {
        const promise = this.compileChannelData(web, id, name).then(
          (channelData) => {
            map.set(id, channelData);
          }
        );

        promises.push(promise);
      }

      return Promise.all(promises).then(() => map);
    });
  }

  /**
   * Compile data for the given channel.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} id The channel id.
   * @param {string} name The name of the channel.
   * @return {Promise<object>} Data related to the channel.
   */
  static compileChannelData(web, id, name) {
    return web.channels.history(id, { count: NUM_CHANNEL_MESSAGES }).then(
      ({ messages }) => {
        const messageInfo = messages.map(({ text, ts: timestamp }) => {
          const rating = computeMessageRating(text);
          return { rating, timestamp };
        });

        const ratings = messageInfo.map(({ rating }) => rating);
        const psychoPass = computeChannelPsychoPass(ratings);

        return { name, psychoPass, messageInfo };
      }
    );
  }

  /**
   * Initialize the user leaderboard.
   *
   * @private
   */
  initializeUserLeaderboard() {
    this.store.users.forEach(({ psychoPass }, id) => {
      this.store.leaderboards.users.update(id, psychoPass);
    });
  }

  /**
   * Initialize the channel leaderboard.
   *
   * @private
   */
  initializeChannelLeaderboard() {
    this.store.channels.forEach(({ psychoPass }, id) => {
      this.store.leaderboards.channels.update(id, psychoPass);
    });
  }

  /**
   * Process a new message.
   *
   * @public
   * @param {string} id The user id of the sender.
   * @param {string} message The body of the message.
   * @param {string} channel The id of the channel to which the message was
   * posted.
   * @param {string} timestamp
   * @return {string|null} The response to be sent to the client or
   * null if there is no response.
   */
  newMessage(id, message, channel, timestamp) {
    this.updateUser(id, message, channel, timestamp);

    const commandInfo = this.parseCommand(message);
    if (commandInfo) {
      switch (commandInfo.command) {
        case 'user':
          return this.psychoPassUser(commandInfo.id);
        case 'channel':
          return this.psychoPassChannel(commandInfo.id);
        case 'help':
          return this.help();
        case 'users':
          return this.leaderboardUsers();
        case 'channels':
          return this.leaderboardChannels();
      }
    }

    return null;
  }

  /**
   * Parse a command from a message.
   *
   * @private
   * @param {string} message
   * @return {object|null} An object containing information about the parsed
   * command if one is found. If no command is found return null.
   */
  parseCommand(message) {
    if (message === 'psychopass') {
      return { command: 'same channel' };
    }

    const command = 'psychopass ';
    if (message.startsWith(command)) {
      const fragment = message.substr(command.length);

      let subCommand = /^<([@#])(.{2,})>/;
      const result = subCommand.exec(fragment);
      if (result) {
        const id = result[2];
        const command = result[1] === '@' ? 'user' : 'channel';

        return { id, command };
      }

      subCommand = /^help(?:\s|$)/;
      if (subCommand.test(fragment)) {
        return { command: 'help' };
      }

      subCommand = 'leaderboard ';
      if (fragment.startsWith(subCommand)) {
        const subFragment = fragment.substr(subCommand.length);

        let command = /^users(?:\s|$)/;
        if (command.test(subFragment)) {
          return { command: 'users' };
        }

        command = /^channels(?:\s|$)/;
        if (command.test(subFragment)) {
          return { command: 'channels' };
        }
      }
    }

    return null;
  }

  /**
   * Produce help message.
   *
   * @private
   * @return {string} The help message.
   */
  help() {
    return 'The following commands are available:\n\n' +
      'psychopass @username\n' +
      'psychopass #channel\n' +
      'psychopass leaderboard users\n' +
      'psychopass leaderboard channels\n' +
      'psychopass help';
  }

  /**
   * Produce response for user leaderboard.
   *
   * @private
   * @return {string} The user leaderboard response.
   */
  leaderboardUsers() {
    const highest = this.store.leaderboards.users.getHighest();
    const lowest = this.store.leaderboards.users.getLowest();

    let s = 'Lowest:\n';
    lowest.forEach(({ id, value: psychoPass }, index) => {
      const username = this.getUserUsername(id);
      s += `${psychoPass} ${username}\n`;
    });

    s += '\nHighest:\n';
    highest.forEach(({ id, value: psychoPass }, index) => {
      const username = this.getUserUsername(id);
      s += `${psychoPass} ${username}\n`;
    });

    return s;
  }

  /**
   * Produce response for channel leaderboard.
   *
   * @private
   * @return {string} The channel leaderboard response.
   */
  leaderboardChannels() {
    const highest = this.store.leaderboards.channels.getHighest();
    const lowest = this.store.leaderboards.channels.getLowest();

    let s = 'Lowest:\n';
    lowest.forEach(({ id, value: psychoPass }, index) => {
      const name = this.getChannelName(id);
      s += `${psychoPass} ${name}\n`;
    });

    s += '\nHighest:\n';
    highest.forEach(({ id, value: psychoPass }, index) => {
      const name = this.getChannelName(id);
      s += `${psychoPass} ${name}\n`;
    });

    return s;
  }

  /**
   * Update stored data and Psycho-Pass of a user based on a new message.
   *
   * @private
   * @param {string} id The user id.
   * @param {string} message
   * @param {string} channel The id of the channel.
   * @param {string} timestamp
   */
  updateUser(id, message, channel, timestamp) {
    const rating = computeMessageRating(message);
    const info = { rating, channel, timestamp };
    const { messageInfo, psychoPass: oldPsychoPass } = this.store.users.get(id);
    const len = messageInfo.unshift(info);

    if (len > NUM_USER_MESSAGES) {
      messageInfo.pop();
    }

    const ratings = messageInfo.map(({ rating }) => rating);
    const newPsychoPass = computeUserPsychoPass(ratings);

    this.store.leaderboards.users.update(
      id,
      newPsychoPass,
      oldPsychoPass
    );
    this.store.users.get(id).psychoPass = newPsychoPass;
  }

  /**
   * Handle a request for the Psycho-Pass of a user and produce a response.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} Response to the request.
   */
  psychoPassUser(id) {
    const name = this.getUserName(id);
    const psychoPass = this.getUserPsychoPass(id);

    return `${name} has a Psycho-Pass of ${psychoPass}`;
  }

  /**
   * Handle a request for the Psycho-Pass of a channel and produce a response.
   *
   * @private
   * @param {string} id The channel id.
   * @return {string} Response to the request.
   */
  psychoPassChannel(id) {
    const name = this.getChannelName(id);
    const psychoPass = this.getChannelPsychoPass(id);

    return `#${name} has a Psycho-Pass of ${psychoPass}`;
  }

  /**
   * Fetch the {NUM_USER_MESSAGES} most recent messages for a user.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} username
   * @return {Promise<object[]>} The message objects.
   */
  static fetchUserMessages(web, username) {
    const query = `from:${username}`;
    const options = { sort: 'timestamp', count: NUM_USER_MESSAGES };

    return web.search.messages(query, options).then(
      ({ messages: { matches: userMessages } }) => {
        const messages = userMessages.map(({
          text: message,
          ts: timestamp,
          channel: { id: channel },
        }) => { message, timestamp, channel });

        return messages;
      }
    );
  }

  /**
   * Get a user's username.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} The user's username.
   */
  getUserUsername(id) {
    return this.store.users.get(id).username;
  }

  /**
   * Get a user's name.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} The user's name.
   */
  getUserName(id) {
    return this.store.users.get(id).name;
  }

  /**
   * Get a user's Psycho-Pass.
   *
   * @private
   * @param {string} id The user id.
   * @return {number} The user's Psycho-Pass.
   */
  getUserPsychoPass(id) {
    return this.store.users.get(id).psychoPass;
  }

  /**
   * Get the name of a channel.
   *
   * @private
   * @param {string} id The channel id.
   * @return {string} The channel name.
   */
  getChannelName(id) {
    return this.store.channels.get(id).name;
  }

  /**
   * Get a channel's Psycho-Pass.
   *
   * @private
   * @param {string} id The channel id.
   * @return {number} The channel's Psycho-Pass.
   */
  getChannelPsychoPass(id) {
    return this.store.channels.get(id).psychoPass;
  }
};
<commit_msg>Fix minor bug<commit_after>import { WebClient } from '@slack/client';

import {
  computeMessageRating,
  computeUserPsychoPass,
  computeChannelPsychoPass,
  NUM_USER_MESSAGES,
  NUM_CHANNEL_MESSAGES,
} from './psychoPass';
import Leaderboard from './leaderboard/Leaderboard';

/**
 * Class responsible for processing input and maintaing the application state.
 * Produces a response to be sent to the client when appropriate.
 */
export default class {
  /**
   * Initialize data store and Slack web client.
   *
   * @param {WebClient} web A WebClient instance.
   * @param {Map<string, object>} userData Map from user id to an object
   * containing user data.
   * @param {Map<string, object>} channelData Map from channel id to an object
   * containing channel data.
   */
  constructor(web, userData, channelData) {
    this.store = {
      users: userData,
      channels: channelData,
      leaderboards: { users: new Leaderboard(), channels: new Leaderboard() },
    };
    this.web = web;

    this.initializeUserLeaderboard();
    this.initializeChannelLeaderboard();
  }

  /**
   * Create an instance of the Sibyl class.
   *
   * @public
   * @param {string} token The Slack API token.
   * @return {Promise<Sibyl>} Instance of Sibyl class.
   */
  static createSibyl(token) {
    const web = new WebClient(token);
    const userData = this.getInitialUserData(web);
    const channelData = this.getInitialChannelData(web);
    const sibyl = Promise.all([userData, channelData]).then(
      ([userData, channelData]) => {
        return new this(web, userData, channelData);
      }
    );

    return sibyl;
  }

  /**
   * Fetch initial user data.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @return {Promise<Map<string, object>>} Map from user id to user data
   * object.
   */
  static getInitialUserData(web) {
    return web.users.list().then(({ members }) => {
      const map = new Map();
      const promises = [];

      for (const { id, name, real_name } of members) {
        const promise = this.compileUserData(web, name, real_name).then(
          (userData) => {
            map.set(id, userData);
          }
        );

        promises.push(promise);
      }

      return Promise.all(promises).then(() => map);
    });
  }

  /**
   * Compile data for the given user.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} username The username by which to identify the user.
   * @param {string} name The name of the user.
   * @return {Promise<object>} Data related to the user.
   */
  static compileUserData(web, username, name) {
    return this.fetchUserMessages(web, username).then((messages) => {
      const messageInfo = messages.map(({ message, channel, timestamp }) => {
        const rating = computeMessageRating(message);
        return { rating, channel, timestamp };
      });
      const ratings = messageInfo.map(({ rating }) => rating);
      const psychoPass = computeUserPsychoPass(ratings);

      return { username, name, psychoPass, messageInfo };
    });
  }

  /**
   * Fetch initial channel data.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @return {Promise<Map<string, object>>} Map from channel id to channel data
   * object.
   */
  static getInitialChannelData(web) {
    return web.channels.list({ exclude_archived: 1 }).then(({ channels }) => {
      const map = new Map();
      const promises = [];

      for (const { id, name } of channels) {
        const promise = this.compileChannelData(web, id, name).then(
          (channelData) => {
            map.set(id, channelData);
          }
        );

        promises.push(promise);
      }

      return Promise.all(promises).then(() => map);
    });
  }

  /**
   * Compile data for the given channel.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} id The channel id.
   * @param {string} name The name of the channel.
   * @return {Promise<object>} Data related to the channel.
   */
  static compileChannelData(web, id, name) {
    return web.channels.history(id, { count: NUM_CHANNEL_MESSAGES }).then(
      ({ messages }) => {
        const messageInfo = messages.map(({ text, ts: timestamp }) => {
          const rating = computeMessageRating(text);
          return { rating, timestamp };
        });

        const ratings = messageInfo.map(({ rating }) => rating);
        const psychoPass = computeChannelPsychoPass(ratings);

        return { name, psychoPass, messageInfo };
      }
    );
  }

  /**
   * Initialize the user leaderboard.
   *
   * @private
   */
  initializeUserLeaderboard() {
    this.store.users.forEach(({ psychoPass }, id) => {
      this.store.leaderboards.users.update(id, psychoPass);
    });
  }

  /**
   * Initialize the channel leaderboard.
   *
   * @private
   */
  initializeChannelLeaderboard() {
    this.store.channels.forEach(({ psychoPass }, id) => {
      this.store.leaderboards.channels.update(id, psychoPass);
    });
  }

  /**
   * Process a new message.
   *
   * @public
   * @param {string} id The user id of the sender.
   * @param {string} message The body of the message.
   * @param {string} channel The id of the channel to which the message was
   * posted.
   * @param {string} timestamp
   * @return {string|null} The response to be sent to the client or
   * null if there is no response.
   */
  newMessage(id, message, channel, timestamp) {
    this.updateUser(id, message, channel, timestamp);

    const commandInfo = this.parseCommand(message);
    if (commandInfo) {
      switch (commandInfo.command) {
        case 'user':
          return this.psychoPassUser(commandInfo.id);
        case 'channel':
          return this.psychoPassChannel(commandInfo.id);
        case 'help':
          return this.help();
        case 'users':
          return this.leaderboardUsers();
        case 'channels':
          return this.leaderboardChannels();
      }
    }

    return null;
  }

  /**
   * Parse a command from a message.
   *
   * @private
   * @param {string} message
   * @return {object|null} An object containing information about the parsed
   * command if one is found. If no command is found return null.
   */
  parseCommand(message) {
    if (message === 'psychopass') {
      return { command: 'same channel' };
    }

    const command = 'psychopass ';
    if (message.startsWith(command)) {
      const fragment = message.substr(command.length);

      let subCommand = /^<([@#])(.{2,})>/;
      const result = subCommand.exec(fragment);
      if (result) {
        const id = result[2];
        const command = result[1] === '@' ? 'user' : 'channel';

        return { id, command };
      }

      subCommand = /^help(?:\s|$)/;
      if (subCommand.test(fragment)) {
        return { command: 'help' };
      }

      subCommand = 'leaderboard ';
      if (fragment.startsWith(subCommand)) {
        const subFragment = fragment.substr(subCommand.length);

        let command = /^users(?:\s|$)/;
        if (command.test(subFragment)) {
          return { command: 'users' };
        }

        command = /^channels(?:\s|$)/;
        if (command.test(subFragment)) {
          return { command: 'channels' };
        }
      }
    }

    return null;
  }

  /**
   * Produce help message.
   *
   * @private
   * @return {string} The help message.
   */
  help() {
    return 'The following commands are available:\n\n' +
      'psychopass @username\n' +
      'psychopass #channel\n' +
      'psychopass leaderboard users\n' +
      'psychopass leaderboard channels\n' +
      'psychopass help';
  }

  /**
   * Produce response for user leaderboard.
   *
   * @private
   * @return {string} The user leaderboard response.
   */
  leaderboardUsers() {
    const highest = this.store.leaderboards.users.getHighest();
    const lowest = this.store.leaderboards.users.getLowest();

    let s = 'Lowest:\n';
    lowest.forEach(({ id, value: psychoPass }, index) => {
      const username = this.getUserUsername(id);
      s += `${psychoPass} ${username}\n`;
    });

    s += '\nHighest:\n';
    highest.forEach(({ id, value: psychoPass }, index) => {
      const username = this.getUserUsername(id);
      s += `${psychoPass} ${username}\n`;
    });

    return s;
  }

  /**
   * Produce response for channel leaderboard.
   *
   * @private
   * @return {string} The channel leaderboard response.
   */
  leaderboardChannels() {
    const highest = this.store.leaderboards.channels.getHighest();
    const lowest = this.store.leaderboards.channels.getLowest();

    let s = 'Lowest:\n';
    lowest.forEach(({ id, value: psychoPass }, index) => {
      const name = this.getChannelName(id);
      s += `${psychoPass} ${name}\n`;
    });

    s += '\nHighest:\n';
    highest.forEach(({ id, value: psychoPass }, index) => {
      const name = this.getChannelName(id);
      s += `${psychoPass} ${name}\n`;
    });

    return s;
  }

  /**
   * Update stored data and Psycho-Pass of a user based on a new message.
   *
   * @private
   * @param {string} id The user id.
   * @param {string} message
   * @param {string} channel The id of the channel.
   * @param {string} timestamp
   */
  updateUser(id, message, channel, timestamp) {
    const rating = computeMessageRating(message);
    const info = { rating, channel, timestamp };
    const { messageInfo, psychoPass: oldPsychoPass } = this.store.users.get(id);
    const len = messageInfo.unshift(info);

    if (len > NUM_USER_MESSAGES) {
      messageInfo.pop();
    }

    const ratings = messageInfo.map(({ rating }) => rating);
    const newPsychoPass = computeUserPsychoPass(ratings);

    this.store.leaderboards.users.update(
      id,
      newPsychoPass,
      oldPsychoPass
    );
    this.store.users.get(id).psychoPass = newPsychoPass;
  }

  /**
   * Handle a request for the Psycho-Pass of a user and produce a response.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} Response to the request.
   */
  psychoPassUser(id) {
    const name = this.getUserName(id);
    const psychoPass = this.getUserPsychoPass(id);

    return `${name} has a Psycho-Pass of ${psychoPass}`;
  }

  /**
   * Handle a request for the Psycho-Pass of a channel and produce a response.
   *
   * @private
   * @param {string} id The channel id.
   * @return {string} Response to the request.
   */
  psychoPassChannel(id) {
    const name = this.getChannelName(id);
    const psychoPass = this.getChannelPsychoPass(id);

    return `#${name} has a Psycho-Pass of ${psychoPass}`;
  }

  /**
   * Fetch the {NUM_USER_MESSAGES} most recent messages for a user.
   *
   * @private
   * @param {WebClient} web A WebClient instance.
   * @param {string} username
   * @return {Promise<object[]>} The message objects.
   */
  static fetchUserMessages(web, username) {
    const query = `from:${username}`;
    const options = { sort: 'timestamp', count: NUM_USER_MESSAGES };

    return web.search.messages(query, options).then(
      ({ messages: { matches: userMessages } }) => {
        const messages = userMessages.map(({
          text: message,
          ts: timestamp,
          channel: { id: channel },
        }) => ({ message, timestamp, channel }));

        return messages;
      }
    );
  }

  /**
   * Get a user's username.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} The user's username.
   */
  getUserUsername(id) {
    return this.store.users.get(id).username;
  }

  /**
   * Get a user's name.
   *
   * @private
   * @param {string} id The user id.
   * @return {string} The user's name.
   */
  getUserName(id) {
    return this.store.users.get(id).name;
  }

  /**
   * Get a user's Psycho-Pass.
   *
   * @private
   * @param {string} id The user id.
   * @return {number} The user's Psycho-Pass.
   */
  getUserPsychoPass(id) {
    return this.store.users.get(id).psychoPass;
  }

  /**
   * Get the name of a channel.
   *
   * @private
   * @param {string} id The channel id.
   * @return {string} The channel name.
   */
  getChannelName(id) {
    return this.store.channels.get(id).name;
  }

  /**
   * Get a channel's Psycho-Pass.
   *
   * @private
   * @param {string} id The channel id.
   * @return {number} The channel's Psycho-Pass.
   */
  getChannelPsychoPass(id) {
    return this.store.channels.get(id).psychoPass;
  }
};
<|endoftext|>


<commit_before>import minimatch from 'minimatch';
import Jungle from 'node-jungle';
import utils from 'node-jungle/lib/utils';

import notifiers from './notifiers';

/**
 * Uncle
 */
export default class Uncle {

  /**
   * constructor
   *
   * @param {Object[]} configs List of Config
   */
  constructor(configs) {
    this.configs = configs;
    this.jungle = new Jungle();
  }

  /**
   * Check AWS Services
   *
   * @return {Promise}
   */
  check() {
    return Promise.all(this.configs.map(target => {
      if (this[target.type]) {
        return this[target.type](target);
      }
      return null;
    })).then(results => {
      return results.filter(result => result.names.length > 0);
    });
  }

  /**
   * Send notification when check results is unexpected
   *
   * @return {Promise}
   */
  scold() {
    return new Promise((resolve, reject) => {
      this.check().then(results => {
        if (results.length > 0) {
          const msg = this.createScoldingMessage(results);
          notifiers.hipchat(msg).catch(err => {
            reject(err);
          }).then(() => resolve(true));
        } else {
          resolve(true);
        }
      });
    });
  }

  /**
   * Return scolding message
   *
   * @param {Object[]} results List of check results
   * @return {string}
   */
  createScoldingMessage(results) {
    const list = results.map(result => {
      return `- ${result.type}: ${result.names.join(', ')}`;
    });
    return `@all hey guys, UNEXPECTED SERVERS are running!
${list.join('\n')}
http://img.tiqav.com/1Mr.jpg`;
  }

  /**
   * Exclude
   *
   * @param {Object[]} instances object list of aws-sdk response
   * @param {Object} condition condition of exclude
   * @param {Function} getter function for getting instance value
   * @return {Object[]}
   */
  exclude(instances, condition, getter) {
    return instances.filter(ins => {
      return !Object.keys(condition).some(key => {
        const con = condition[key];
        const val = getter(ins, key);
        if (val === undefined) {
          return false;
        }
        return (Array.isArray(con) ? con : [con]).some(c => minimatch(val, c));
      });
    });
  }

  /**
   * Check for Elastic Beanstalk
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  eb(target) {
    return this.jungle.eb.getEnvironments(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.EnvironmentName;
        } else if (key === 'cname') {
          return i.CNAME;
        }
      }).map(i => i.EnvironmentName);
      return {type: 'EB', names};
    });
  }

  /**
   * Check for EC2
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  ec2(target) {
    return this.jungle.ec2.getInstances(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return utils.getTagValue(i.Tags, 'Name') || '';
        }
      }).map(i => utils.getTagValue(i.Tags, 'Name') || '');
      return {type: 'EC2', names};
    });
  }

  /**
   * Check for EMR
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  emr(target) {
    return this.jungle.emr.getClusters(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.Name;
        } else if (key === 'stateName') {
          return i.Status.State;
        }
      }).map(i => i.Name);
      return {type: 'EMR', names};
    });
  }

  /**
   * Check for RDS
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  rds(target) {
    return this.jungle.rds.getInstances(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.DBInstanceIdentifier;
        }
      }).map(i => i.DBInstanceIdentifier);
      return {type: 'RDS', names};
    });
  }
}
<commit_msg>refactor(Uncle): Fix code styles for eslint/consistent-return<commit_after>import minimatch from 'minimatch';
import Jungle from 'node-jungle';
import utils from 'node-jungle/lib/utils';

import notifiers from './notifiers';

/**
 * Uncle
 */
export default class Uncle {

  /**
   * constructor
   *
   * @param {Object[]} configs List of Config
   */
  constructor(configs) {
    this.configs = configs;
    this.jungle = new Jungle();
  }

  /**
   * Check AWS Services
   *
   * @return {Promise}
   */
  check() {
    return Promise.all(this.configs.map(target => {
      if (this[target.type]) {
        return this[target.type](target);
      }
      return null;
    })).then(results => {
      return results.filter(result => result.names.length > 0);
    });
  }

  /**
   * Send notification when check results is unexpected
   *
   * @return {Promise}
   */
  scold() {
    return new Promise((resolve, reject) => {
      this.check().then(results => {
        if (results.length > 0) {
          const msg = this.createScoldingMessage(results);
          notifiers.hipchat(msg).catch(err => {
            reject(err);
          }).then(() => resolve(true));
        } else {
          resolve(true);
        }
      });
    });
  }

  /**
   * Return scolding message
   *
   * @param {Object[]} results List of check results
   * @return {string}
   */
  createScoldingMessage(results) {
    const list = results.map(result => {
      return `- ${result.type}: ${result.names.join(', ')}`;
    });
    return `@all hey guys, UNEXPECTED SERVERS are running!
${list.join('\n')}
http://img.tiqav.com/1Mr.jpg`;
  }

  /**
   * Exclude
   *
   * @param {Object[]} instances object list of aws-sdk response
   * @param {Object} condition condition of exclude
   * @param {Function} getter function for getting instance value
   * @return {Object[]}
   */
  exclude(instances, condition, getter) {
    return instances.filter(ins => {
      return !Object.keys(condition).some(key => {
        const con = condition[key];
        const val = getter(ins, key);
        if (val === undefined) {
          return false;
        }
        return (Array.isArray(con) ? con : [con]).some(c => minimatch(val, c));
      });
    });
  }

  /**
   * Check for Elastic Beanstalk
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  eb(target) {
    return this.jungle.eb.getEnvironments(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.EnvironmentName;
        } else if (key === 'cname') {
          return i.CNAME;
        }
        return undefined;
      }).map(i => i.EnvironmentName);
      return {type: 'EB', names};
    });
  }

  /**
   * Check for EC2
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  ec2(target) {
    return this.jungle.ec2.getInstances(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return utils.getTagValue(i.Tags, 'Name') || '';
        }
        return undefined;
      }).map(i => utils.getTagValue(i.Tags, 'Name') || '');
      return {type: 'EC2', names};
    });
  }

  /**
   * Check for EMR
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  emr(target) {
    return this.jungle.emr.getClusters(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.Name;
        } else if (key === 'stateName') {
          return i.Status.State;
        }
        return undefined;
      }).map(i => i.Name);
      return {type: 'EMR', names};
    });
  }

  /**
   * Check for RDS
   *
   * @param {Object} target Config object
   * @return {Promise}
   */
  rds(target) {
    return this.jungle.rds.getInstances(target.filter).then(instances => {
      const names = this.exclude(instances, target.exclude, (i, key) => {
        if (key === 'name') {
          return i.DBInstanceIdentifier;
        }
        return undefined;
      }).map(i => i.DBInstanceIdentifier);
      return {type: 'RDS', names};
    });
  }
}
<|endoftext|>


<commit_before>var React = require('react');

var Option = React.createClass({

	displayName: 'Value',

	propTypes: {
		label: React.PropTypes.string.isRequired,
		onRemove: React.PropTypes.func,
		optionLabelClick: React.PropTypes.bool,
		onOptionLabelClick: React.PropTypes.func
	},

	blockEvent: function(event) {
		event.stopPropagation();
	},

	render: function() {
		var label = this.props.label;

		if (this.props.optionLabelClick) {
			label = (

					{label}

			);
		}

		return (

				×
				{label}

		);
	}

});

module.exports = Option;
<commit_msg>Fixing propType order<commit_after>var React = require('react');

var Option = React.createClass({

	displayName: 'Value',

	propTypes: {
		label: React.PropTypes.string.isRequired,
		onOptionLabelClick: React.PropTypes.func,
		onRemove: React.PropTypes.func,
		optionLabelClick: React.PropTypes.bool
	},

	blockEvent: function(event) {
		event.stopPropagation();
	},

	render: function() {
		var label = this.props.label;

		if (this.props.optionLabelClick) {
			label = (

					{label}

			);
		}

		return (

				×
				{label}

		);
	}

});

module.exports = Option;
<|endoftext|>


<commit_before>/**
 * @fileoverview Soundworks server side time synchronization module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var ServerModule = require('./ServerModule');
var Sync = require('sync/server');

class ServerSync extends ServerModule {
  constructor(options = {}) {
    super();
    this.sync = new Sync(options);
  }

  connect(client) {
    super.connect();

    this.sync.start(client.socket);
  }

  getLocalTime(syncTime) {
    return this.sync.getLocalTime(syncTime);
  }

  getSyncTime(localTime) {
    return this.sync.getSyncTime(localTime);
  }

} // class ServerSync

module.exports = ServerSync;
<commit_msg>adapted server side sync module to latest changes of the sync component<commit_after>/**
 * @fileoverview Soundworks server side time synchronization module
 * @author Sebastien.Robaszkiewicz@ircam.fr, Norbert.Schnell@ircam.fr
 */
'use strict';

var ServerModule = require('./ServerModule');
var Sync = require('sync/server');

class ServerSync extends ServerModule {
  constructor(options = {}) {
    super();
    this.sync = new Sync(() => {
      let time = process.hrtime();
      return time[0] + time[1] * 1e-9;
    }, (cmd, ...args) => {
        client.send(cmd, ...args);
      }, (cmd, callback) => {
        client.receive(cmd, callback);
      });
  }

  connect(client) {
    super.connect();
    this.sync.start(client.socket);
  }

  getLocalTime(syncTime) {
    return this.sync.getLocalTime(syncTime);
  }

  getSyncTime(localTime) {
    return this.sync.getSyncTime(localTime);
  }

} // class ServerSync

module.exports = ServerSync;<|endoftext|>


<commit_before>API = {
  authentication: function(apiKey){
    return apiKey === Meteor.settings.PNCTSRC_ACCESS_KEY;
  },
  connection: function(request){
    var getRequestContents = API.utility.getRequestContents(request),
        apiKey = getRequestContents.api_key,
        validUser = API.authentication(apiKey);

    if(validUser){
      delete getRequestContents.api_key;
      return {
        data: getRequestContents
      }
    } else {
      return {
        error: 401,
        message: "Invalid access key."
      }
    }
  },
  handleRequest: function(context, resource, method){
    var connection = API.connection(context.request);
    if(!connection.error){
      API.methods[resource][method](context, connection);
    } else {
      API.utility.response(context, 401, connection);
    }
  },
  methods: {
    pic: {
      GET: function(context, connection){},
      POST: function(context, connection){
        var Busboy = require('busboy');
        var path = require('path');
        var fs = require('fs');
        var busboy = new Busboy({headers: context.request.headers});

        var final_filename;
        var ifError = false;//true if any error happens later
        busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
          const fileExtension = mimetype.substring(6).replace("e", "");

          //validate the file
          var file_size = 0;
          file.on('data', function(data){
            file_size += data.length;

            if(file_size > 10485760){
              API.utility.sendError(context, 400, "Image size larger than 10MB.");
              ifError = true;
            }
          })

          if(_.indexOf(["jpg", "jpeg", "png"], fileExtension) === -1){
            API.utility.sendError(context, 400, "Image type not allowed.");
            ifError = true;
          }

          if(ifError) return;

          final_filename = (new Date()).getTime() + "." + fileExtension;
          var saveTo = Meteor.settings.IMAGE_PATH + final_filename;

          file.pipe(fs.createWriteStream(saveTo));
        });

        busboy.on('finish', function() {
          if(ifError) return;

          API.utility.response(context, 200, {link: "http://localhost:3000/resources/images/" + final_filename});
        });

        context.request.pipe(busboy);
      },
      PUT: function(context, connection){},
      DELETE: function(context, connection){}
    }
  },
  resources: {},
  utility: {
    getRequestContents: function(request){
      switch (request.method){
        case "GET":
        case "POST":
          return request.query;
        case "PUT":
        case "DELETE":
          return request.body;
      }
    },
    hasData: function(data){
      return Object.keys(data).length > 0 ? true : false;
    },
    response: function(context, statusCode, data){
      context.response.setHeader('Content-Type', 'application/json');
      context.response.statusCode = statusCode;
      context.response.end(JSON.stringify(data));
    },
    validate: function(data, pattern){
      return Match.test(data, pattern);
    },
    sendError: function(context, statusCode, message){
      API.utility.response(context, statusCode, {
        error: 400,
        message: message
      });
    }
  }
};
<commit_msg>Image delete API added<commit_after>API = {
  authentication: function(apiKey){
    return apiKey === Meteor.settings.PNCTSRC_ACCESS_KEY;
  },
  connection: function(request){
    var getRequestContents = API.utility.getRequestContents(request),
        apiKey = getRequestContents.api_key,
        validUser = API.authentication(apiKey);

    if(validUser){
      delete getRequestContents.api_key;
      return {
        data: getRequestContents
      }
    } else {
      return {
        error: 401,
        message: "Invalid access key."
      }
    }
  },
  handleRequest: function(context, resource, method){
    var connection = API.connection(context.request);
    if(!connection.error){
      API.methods[resource][method](context, connection);
    } else {
      API.utility.response(context, 401, connection);
    }
  },
  methods: {
    pic: {
      GET: function(context, connection){},
      POST: function(context, connection){
        var Busboy = require('busboy');
        var path = require('path');
        var fs = require('fs');
        var busboy = new Busboy({headers: context.request.headers});

        var final_filename;
        var ifError = false;//true if any error happens later
        busboy.on('file', function(fieldname, file, filename, encoding, mimetype) {
          const fileExtension = mimetype.substring(6).replace("e", "");

          //validate the file
          var file_size = 0;
          file.on('data', function(data){
            file_size += data.length;

            if(file_size > 10485760){
              API.utility.sendError(context, 400, "Image size larger than 10MB.");
              ifError = true;
            }
          })

          if(_.indexOf(["jpg", "jpeg", "png"], fileExtension) === -1){
            API.utility.sendError(context, 400, "Image type not allowed.");
            ifError = true;
          }

          if(ifError) return;

          final_filename = (new Date()).getTime() + "." + fileExtension;
          var saveTo = Meteor.settings.IMAGE_PATH + final_filename;

          file.pipe(fs.createWriteStream(saveTo));
        });

        busboy.on('finish', function() {
          if(ifError) return;

          API.utility.response(context, 200, {link: "http://localhost:3000/resources/images/" + final_filename});
        });

        context.request.pipe(busboy);
      },
      PUT: function(context, connection){},
      DELETE: function(context, connection){
        var fs = require('fs');
        const fileName = connection.data.src.substring(connection.data.src.lastIndexOf('/') + 1);
        const path = Meteor.settings.IMAGE_PATH + fileName;

        //check if the file exists
        if(fs.existsSync(path)){
          fs.unlinkSync(path);
          API.utility.response(context, 200, {message: "Success."});
        } else {
          API.utility.sendError(context, 404, "No such Image");
        }
      }
    }
  },
  resources: {},
  utility: {
    getRequestContents: function(request){
      switch (request.method){
        case "GET":
        case "POST":
          return request.query;
        case "PUT":
        case "DELETE":
          return request.body;
      }
    },
    hasData: function(data){
      return Object.keys(data).length > 0 ? true : false;
    },
    response: function(context, statusCode, data){
      context.response.setHeader('Content-Type', 'application/json');
      context.response.statusCode = statusCode;
      context.response.end(JSON.stringify(data));
    },
    validate: function(data, pattern){
      return Match.test(data, pattern);
    },
    sendError: function(context, statusCode, message){
      API.utility.response(context, statusCode, {
        error: 400,
        message: message
      });
    }
  }
};
<|endoftext|>


<commit_before>const express = require('express');
const router = express.Router();
const _ = require('lodash');
const request = require("request");
const checkJwt = require('./../checkJwt');
const config = require('./../../config');
const models = require('../models');
const net = require('net');
const cache = require('apicache').middleware;

function getLastHints(callback) {
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => _.last(sortedHint));

    callback(lastHints);
  });
}

/**
  Perform a call to Projection, a location prediction API.
*/
router.get('/', cache('5 minute'), (req, res) => {
  getLastHints((lastHints) => {
    // Prepare object array for Projection API.
    const requestBody = {
      lastLocations: _.map(lastHints, (hint) => {
        return {
          subarea: hint.Subarea.name.toLowerCase(),
          location: [hint.latitude, hint.longitude],
          timestamp: hint.createdAt
        };
      })
    }

    try {
      // Perform request to Projection API over a socket.
      const client = new net.Socket();
      client.connect(31337, '142.93.137.62', () => {
        console.log("[+] Requesting Projection API");
        client.write(JSON.stringify(requestBody));
      });

      // Receive data
      let data = '';
      client.on('data', (chunk) => {
        data += chunk;
      });

      // Send data to client on response end.
      client.on('end', () => {
        try {
          const parsedData = JSON.parse(data);
          // Send data to client
          res.send(JSON.stringify(parsedData));
        } catch (error) {
          console.error("[-] Error on retrieving Projection API")
          console.error(error);
          res.status(500).send(error);
        }
      });

      client.on('error', (error) => {
        res.status(500).send(error);
      });
    } catch (error) {
      console.log(error);
      res.status(500).send(error);
    }
  });
});

module.exports = router;
<commit_msg>Update prediction.js<commit_after>const express = require('express');
const router = express.Router();
const _ = require('lodash');
const request = require("request");
const checkJwt = require('./../checkJwt');
const config = require('./../../config');
const models = require('../models');
const net = require('net');
const cache = require('apicache').middleware;

function getLastHints(callback) {
  models.Hint.findAll({
    include: [{
      model: models.HintType,
    }, models.User, models.Subarea],
  }).then((hints) => {
    const groupedHints = _.groupBy(hints, 'Subarea.name');

    const groupedHintsList = [];

    const sort = _.keys(groupedHints).sort();

    for (const i in sort) {
      groupedHintsList.push(groupedHints[sort[i]]);
    }

    const sortedHints = _.map(groupedHintsList, (groupedHint) => _.sortBy(groupedHint, ['createdAt']));

    const lastHints = _.map(sortedHints, (sortedHint) => _.last(sortedHint));

    callback(lastHints);
  });
}

/**
  Perform a call to Projection, a location prediction API.
*/
router.get('/', cache('5 minute'), (req, res) => {
  getLastHints((lastHints) => {
    // Prepare object array for Projection API.
    const requestBody = {
      lastLocations: _.map(lastHints, (hint) => {
        return {
          subarea: hint.Subarea.name.toLowerCase(),
          location: [hint.latitude, hint.longitude],
          timestamp: hint.createdAt
        };
      })
    }

    try {
      // Perform request to Projection API over a socket.
      const client = new net.Socket();
      client.connect(31337, 'localhost', () => {
        console.log("[+] Requesting Projection API");
        client.write(JSON.stringify(requestBody));
      });

      // Receive data
      let data = '';
      client.on('data', (chunk) => {
        data += chunk;
      });

      // Send data to client on response end.
      client.on('end', () => {
        try {
          const parsedData = JSON.parse(data);
          // Send data to client
          res.send(JSON.stringify(parsedData));
        } catch (error) {
          console.error("[-] Error on retrieving Projection API")
          console.error(error);
          res.status(500).send(error);
        }
      });

      client.on('error', (error) => {
        res.status(500).send(error);
      });
    } catch (error) {
      console.log(error);
      res.status(500).send(error);
    }
  });
});

module.exports = router;
<|endoftext|>