<commit_before>var _ = require('underscore');
var github = require('octonode');
var moment = require('moment');
var request = require('request');
var Q = require('q');
var path = require('path');

module.exports = function (mongoRepository, qdService) {

    var logger;
    var self = this;

    this.checkToken = function(userInfo, requestFunction, localLogger){
        var deferred = Q.defer();
        var options = {
            url: "https://api.github.com/user/emails?access_token=" + userInfo.accessToken,
            headers: {
                "User-Agent": "1self"
            }
        };

        requestFunction(options, function (err, res) {
            if(err || res === undefined || res.statusCode !== 200){
                localLogger.logError(userInfo.githubUsername, JSON.stringify(res));
                localLogger.logError(userInfo.githubUsername, 'token is invalid');
                var result = {
                        message: err,
                        code: 500
                };

                // it's likely when a sync error is seen that the github api is preventing token attacks
                if(res.statusCode === 401){
                    result.code = 401;
                }

                localLogger.logError(userInfo.githubUsername, result);
                deferred.reject(result);
            }
            else{
                localLogger.logInfo(userInfo.githubUsername, 'token is valid');
                deferred.resolve(res);
            }
        });
        return deferred.promise;
    };

    var getGithubPushEventsPerPage = function (page, userInfo) {

        var githubUsername = userInfo.githubUsername;
        var user_api_url = '/users/' + githubUsername;
        var client = github.client(userInfo.accessToken);
        logger.logDebug(userInfo.githubUsername, 'fetching page [page, user_api_url, accessToken]', [page, user_api_url, userInfo.accessToken.substring(0,2)]);
        client.get(user_api_url, {}, function () {
        });
        var githubUser = client.user(githubUsername);

        var deferred = Q.defer();
        githubUser.events(page, ['PushEvent'], function (err, pushEvents) {
            if (err) {
                logger.logError(githubUsername, 'err ' + err);
                deferred.reject(err);
            } else {
                deferred.resolve(pushEvents);
            }
        });
        return deferred.promise;
    };

    var fetchGithubPushEvents = function (userInfo) {
        var deferred = Q.defer();
        var pages = _.range(1, 11);
        var promiseArray = _.map(pages, function (page) {
            return getGithubPushEventsPerPage(page, userInfo);
        });
        Q.all(promiseArray)
            .then(_.flatten)
            .then(function (events) {
                deferred.resolve(events);
            });
        return deferred.promise;
    };

    var filterEventsToBeSent = function (userInfo, events, lastSyncDate) {
        logger.logDebug(userInfo.githubUsername, 'filtering events, [event count, lastSyncDate]', [events.length, lastSyncDate]);
        var eventsToBeSent = function (event) {
            return moment(event.created_at).isAfter(lastSyncDate);
        };
        var result = _.filter(events, eventsToBeSent);
        logger.logDebug(userInfo.githubUsername, 'events filtered, [event count]', [events.length]);
        return result;
    };

    var convertEventsTo1SelfFormat = function (filteredEvents, username) {

        var convertEventTo1SelfFormat = function (acc, event) {
            logger.logSilly(username, 'converting raw event: ', event);
            if (event.type === 'PushEvent') {
                var singleEventTemplate = {
                    'actionTags': [
                        'push'
                    ],
                    'objectTags': [
                        'git',
                        'github',
                        'computer',
                        'software',
                        'source-control'
                    ],
                    'id': event.payload.push_id,
                    'childIds': _.map(event.payload.commits, function (c) {
                            return c.sha;
                        }),
                    'dateTime': moment(event.created_at).toISOString(),
                    'latestSyncField': {
                        '$date': moment(event.created_at).toISOString()
                    },
                    'properties': {
                        'commits': event.payload.size,
                        'repo': event.repo.name
                    }
                };

                logger.logSilly(username, 'converted push event: ', singleEventTemplate);
                return acc.concat(singleEventTemplate);

            }
            else if (event.commit !== undefined) {
                var extensionStats = _.reduce(event.files, function(result, file){
                    var ext = path.extname(file.filename).substring(1);
                    result[ext] = result[ext] || {};
                    result[ext]['line-additions'] = (result[ext]['line-additions'] || 0) + file.additions;
                    result[ext]['line-deletions'] = (result[ext]['line-deletions'] || 0) + file.deletions;
                    result[ext]['line-changes'] = (result[ext]['line-changes'] || 0) + file.changes;
                    return result;
                }, {});
                var commitEventTemplate = {
                    'actionTags': [
                        'commit'
                    ],
                    'objectTags': [
                        'git',
                        'github',
                        'computer',
                        'software',
                        'source-control'
                    ],
                    'dateTime': moment(event.commit.author.date).toISOString(),
                    'latestSyncField': {
                        '$date': moment(event.commit.author.date).toISOString()
                    },
                    'id': event.sha,
                    'parentId': event.pushId,
                    'url': event.commit.url,
                    'info': {
                        'message': event.commit.message,
                        'author-name': event.commit.author.name,
                        'author-email': event.commit.author.email,
                        'author-date': event.commit.author.date
                    },
                    'properties': {
                        'line-changes': event.stats.total,
                        'line-additions': event.stats.additions,
                        'line-deletions': event.stats.deletions,
                        'file-changes': event.files.length,
                        'repo': event.repo,
                        'file-types': extensionStats
                    }
                };

                if(event.committerIsAuthor === false){
                    commitEventTemplate.actionTags = ['merge'];
                }

                if (event.commit.author.email !== event.commit.committer.email) {
                    commitEventTemplate.actionTags = ['patch'];
                }

                logger.logSilly(username, 'converted commit event: ', commitEventTemplate);

                return acc.concat(commitEventTemplate);
            }
            else {
                logger.logSilly(username, 'couldnt convert as event is not a push or commit');
                return acc;
            }
        };

        var mappedEvents = _.reduce(filteredEvents, convertEventTo1SelfFormat, []);
        logger.logDebug(username, 'mapped events to 1self format, [event count]', mappedEvents.length);

        return mappedEvents;
    };

    var sendEventsToQD = function (events, streamInfo, appUri, userInfo) {
        var deferred = Q.defer();
        if (_.isEmpty(events)) {
            logger.logDebug(userInfo.githubUsername, 'there are no events to send');
            deferred.resolve();
            return;
        }

        logger.logDebug(userInfo.githubUsername, 'sending events to qd [event count, app uri]', [events.length, appUri]);
        qdService.sendBatchEvents(events, streamInfo, appUri)
            .then(function () {
                logger.logDebug(userInfo.githubUsername, 'events sent to 1self, [event count, stream info]', [events.length, streamInfo]);
                deferred.resolve();
            }, function (error) {
                logger.logError(userInfo.githubUsername, 'error while sending events', error);
                deferred.reject(error);
            });
        return deferred.promise;
    };

    var createSyncStartEvent = function () {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['start'],
            'properties': {}
        };
    };

    var createSyncErrorEvent = function (code) {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['error'],
            'properties': {
                code: code,
                reauth: process.env.GITHUB_INT_CONTEXT_URI + '/reauth'
            }
        };
    };

    var createSyncCompleteEvent = function () {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['complete'],
            'properties': {}
        };
    };

    var getGithubCommitEvents = function (filteredEvents, userInfo) {
        logger.logDebug(userInfo.githubUsername, 'getting commit events for push events, [event count]', filteredEvents.length);
        var deferred = Q.defer();

        var commitObjects = [];

        var userEmailParts = /(.*?)(\+.*?)?(@.*)/g.exec(userInfo.email);
        var userEmail = userEmailParts ? userEmailParts[1] + userEmailParts[3] : null;

        logger.logDebug(userInfo.githubUsername, 'flattening commits');
        logger.logDebug(userInfo.githubUsername, 'removing push email alias, [original, unaliased]', [userInfo.email, userEmail]);

        _.each(filteredEvents, function (event) {
            _.each(event.payload.commits, function (commit) {
                var commitReq = {
                    url: commit.url,
                    pushId: event.payload.push_id,
                    repo: event.repo.name
                };

                commitReq.committerIsAuthor = true;

                if(userEmail){
                    var commitEmailParts = /(.*?)(\+.*?)?(@.*)/g.exec(commit.author.email);
                    var commitEmail = commitEmailParts[1] + commitEmailParts[3];
                    if(commitEmailParts.length === 4){
                        commitReq.committerIsAuthor = commitEmail === userEmail;
                    }
                }

                logger.logDebug(userInfo.githubUsername, 'commit req', commitReq);
                commitObjects.push(commitReq);
            });
        });

        logger.logDebug(userInfo.githubUsername, 'commit have been flattened, [commits]', commitObjects);

        // the delay is in there as the github api is returning an error when hit with lots of requests
        // quickly.
        var getCommitPromise = function (commitObject, delay) {
            var deferred = Q.defer();
            var url = commitObject.url + '?access_token=' + userInfo.accessToken;
            var options = {
                url: url,
                headers: {
                    'User-Agent': '1self'
                }
            };

            setTimeout(function(){
                logger.logDebug(userInfo.githubUsername, [options.url, 'requesting commit, [options, delay]'].join(': '), [options, delay]);
                request(options, function (err, res, body) {
                    if (!err) {
                        logger.logDebug(userInfo.githubUsername, [options.url, 'request successful'].join(': '));
                        var commit = JSON.parse(body);
                        commit.pushId = commitObject.pushId;
                        commit.repo = commitObject.repo;
                        commit.committerIsAuthor = commitObject.committerIsAuthor;
                        deferred.resolve(commit);
                    }
                    else {
                        logger.logDebug(userInfo.githubUsername, [options.url, 'request failed, [error]'].join(': '), err);
                        deferred.reject(err);
                    }
                }).end();
            },
            delay);
            return deferred.promise;
        };

        var promiseArray = [];

        _.map(commitObjects, function (commitObject, i) {
                promiseArray.push(getCommitPromise(commitObject, i * 100));
        });

        Q.all(promiseArray).then(function (commitEvents) {
            logger.logDebug(userInfo.githubUsername, 'all commit events retrieved');
            var events = filteredEvents.concat(commitEvents);
            deferred.resolve(events);
        }).catch(function (error) {
            logger.logError(userInfo.githubUsername, 'Error occurred :: getGithubCommitEvents', error);
        });

        return deferred.promise;
    };

    this.sendGithubEvents = function (userInfo, streamInfo, appUri) {
        logger.logInfo(userInfo.githubUsername, 'starting sync, sending start sync event, [appUri]', [appUri]);
        var syncStartEvent = createSyncStartEvent();

        qdService.sendEvent(syncStartEvent, streamInfo, appUri)
            .then(function(){
                logger.logInfo(userInfo.githubUsername, 'testing token validity');
                logger.logInfo(userInfo.githubUsername, userInfo);
                return self.checkToken(userInfo, request, logger);
            })
            .then(function () {
                logger.logInfo(userInfo.githubUsername, 'fetching events from github api', []);
                return fetchGithubPushEvents(userInfo);
            })
            .then(function (events) {
                logger.logInfo(userInfo.githubUsername, 'filtering events to include only pushes, [event count]', [events.length]);
                return filterEventsToBeSent(userInfo, events, streamInfo.lastSyncDate);
            })
            .then(function (filteredEvents) {
                logger.logInfo(userInfo.githubUsername, 'getting the commit events for the pushes, [event count]', filteredEvents.length);
                return getGithubCommitEvents(filteredEvents, userInfo);
            })
            .then(function (filteredEvents){
                logger.logInfo(userInfo.githubUsername, 'converting events to 1self format, [event count]', filteredEvents.length);
                return convertEventsTo1SelfFormat(filteredEvents, userInfo.githubUsername);
            })
            .then(function (eventsToBeSent) {
                logger.logInfo(userInfo.githubUsername, 'sending the events to 1self, [event count]', eventsToBeSent.length);
                return sendEventsToQD(eventsToBeSent, streamInfo, appUri, userInfo);
            })
            .then(function () {
                logger.logInfo(userInfo.githubUsername, 'sending sync complete to 1self', []);
                var syncCompleteEvent = createSyncCompleteEvent();
                return qdService.sendEvent(syncCompleteEvent, streamInfo, appUri);
            })
            .then(function() {
                logger.logInfo(userInfo.githubUsername, 'finished sending events to 1self');
            })
            .catch(function (error) {
                logger.logError(userInfo.githubUsername, 'Error occurred :: sendGithubEvents', error);
                if(error.code === 401){
                    logger.logError(userInfo.githubUsername, 'sending error event');
                    var errorEvent = createSyncErrorEvent(error.code);
                    return qdService.sendEvent(errorEvent, streamInfo, appUri);
                }
            })
            .done() ;
    };

    this.setLogger = function(newLogger){
        logger = newLogger;
    };

};
<commit_msg>moved email check into guard<commit_after>var _ = require('underscore');
var github = require('octonode');
var moment = require('moment');
var request = require('request');
var Q = require('q');
var path = require('path');

module.exports = function (mongoRepository, qdService) {

    var logger;
    var self = this;

    this.checkToken = function(userInfo, requestFunction, localLogger){
        var deferred = Q.defer();
        var options = {
            url: "https://api.github.com/user/emails?access_token=" + userInfo.accessToken,
            headers: {
                "User-Agent": "1self"
            }
        };

        requestFunction(options, function (err, res) {
            if(err || res === undefined || res.statusCode !== 200){
                localLogger.logError(userInfo.githubUsername, JSON.stringify(res));
                localLogger.logError(userInfo.githubUsername, 'token is invalid');
                var result = {
                        message: err,
                        code: 500
                };

                // it's likely when a sync error is seen that the github api is preventing token attacks
                if(res.statusCode === 401){
                    result.code = 401;
                }

                localLogger.logError(userInfo.githubUsername, result);
                deferred.reject(result);
            }
            else{
                localLogger.logInfo(userInfo.githubUsername, 'token is valid');
                deferred.resolve(res);
            }
        });
        return deferred.promise;
    };

    var getGithubPushEventsPerPage = function (page, userInfo) {

        var githubUsername = userInfo.githubUsername;
        var user_api_url = '/users/' + githubUsername;
        var client = github.client(userInfo.accessToken);
        logger.logDebug(userInfo.githubUsername, 'fetching page [page, user_api_url, accessToken]', [page, user_api_url, userInfo.accessToken.substring(0,2)]);
        client.get(user_api_url, {}, function () {
        });
        var githubUser = client.user(githubUsername);

        var deferred = Q.defer();
        githubUser.events(page, ['PushEvent'], function (err, pushEvents) {
            if (err) {
                logger.logError(githubUsername, 'err ' + err);
                deferred.reject(err);
            } else {
                deferred.resolve(pushEvents);
            }
        });
        return deferred.promise;
    };

    var fetchGithubPushEvents = function (userInfo) {
        var deferred = Q.defer();
        var pages = _.range(1, 11);
        var promiseArray = _.map(pages, function (page) {
            return getGithubPushEventsPerPage(page, userInfo);
        });
        Q.all(promiseArray)
            .then(_.flatten)
            .then(function (events) {
                deferred.resolve(events);
            });
        return deferred.promise;
    };

    var filterEventsToBeSent = function (userInfo, events, lastSyncDate) {
        logger.logDebug(userInfo.githubUsername, 'filtering events, [event count, lastSyncDate]', [events.length, lastSyncDate]);
        var eventsToBeSent = function (event) {
            return moment(event.created_at).isAfter(lastSyncDate);
        };
        var result = _.filter(events, eventsToBeSent);
        logger.logDebug(userInfo.githubUsername, 'events filtered, [event count]', [events.length]);
        return result;
    };

    var convertEventsTo1SelfFormat = function (filteredEvents, username) {

        var convertEventTo1SelfFormat = function (acc, event) {
            logger.logSilly(username, 'converting raw event: ', event);
            if (event.type === 'PushEvent') {
                var singleEventTemplate = {
                    'actionTags': [
                        'push'
                    ],
                    'objectTags': [
                        'git',
                        'github',
                        'computer',
                        'software',
                        'source-control'
                    ],
                    'id': event.payload.push_id,
                    'childIds': _.map(event.payload.commits, function (c) {
                            return c.sha;
                        }),
                    'dateTime': moment(event.created_at).toISOString(),
                    'latestSyncField': {
                        '$date': moment(event.created_at).toISOString()
                    },
                    'properties': {
                        'commits': event.payload.size,
                        'repo': event.repo.name
                    }
                };

                logger.logSilly(username, 'converted push event: ', singleEventTemplate);
                return acc.concat(singleEventTemplate);

            }
            else if (event.commit !== undefined) {
                var extensionStats = _.reduce(event.files, function(result, file){
                    var ext = path.extname(file.filename).substring(1);
                    result[ext] = result[ext] || {};
                    result[ext]['line-additions'] = (result[ext]['line-additions'] || 0) + file.additions;
                    result[ext]['line-deletions'] = (result[ext]['line-deletions'] || 0) + file.deletions;
                    result[ext]['line-changes'] = (result[ext]['line-changes'] || 0) + file.changes;
                    return result;
                }, {});
                var commitEventTemplate = {
                    'actionTags': [
                        'commit'
                    ],
                    'objectTags': [
                        'git',
                        'github',
                        'computer',
                        'software',
                        'source-control'
                    ],
                    'dateTime': moment(event.commit.author.date).toISOString(),
                    'latestSyncField': {
                        '$date': moment(event.commit.author.date).toISOString()
                    },
                    'id': event.sha,
                    'parentId': event.pushId,
                    'url': event.commit.url,
                    'info': {
                        'message': event.commit.message,
                        'author-name': event.commit.author.name,
                        'author-email': event.commit.author.email,
                        'author-date': event.commit.author.date
                    },
                    'properties': {
                        'line-changes': event.stats.total,
                        'line-additions': event.stats.additions,
                        'line-deletions': event.stats.deletions,
                        'file-changes': event.files.length,
                        'repo': event.repo,
                        'file-types': extensionStats
                    }
                };

                if(event.committerIsAuthor === false){
                    commitEventTemplate.actionTags = ['merge'];
                }

                if (event.commit.author.email !== event.commit.committer.email) {
                    commitEventTemplate.actionTags = ['patch'];
                }

                logger.logSilly(username, 'converted commit event: ', commitEventTemplate);

                return acc.concat(commitEventTemplate);
            }
            else {
                logger.logSilly(username, 'couldnt convert as event is not a push or commit');
                return acc;
            }
        };

        var mappedEvents = _.reduce(filteredEvents, convertEventTo1SelfFormat, []);
        logger.logDebug(username, 'mapped events to 1self format, [event count]', mappedEvents.length);

        return mappedEvents;
    };

    var sendEventsToQD = function (events, streamInfo, appUri, userInfo) {
        var deferred = Q.defer();
        if (_.isEmpty(events)) {
            logger.logDebug(userInfo.githubUsername, 'there are no events to send');
            deferred.resolve();
            return;
        }

        logger.logDebug(userInfo.githubUsername, 'sending events to qd [event count, app uri]', [events.length, appUri]);
        qdService.sendBatchEvents(events, streamInfo, appUri)
            .then(function () {
                logger.logDebug(userInfo.githubUsername, 'events sent to 1self, [event count, stream info]', [events.length, streamInfo]);
                deferred.resolve();
            }, function (error) {
                logger.logError(userInfo.githubUsername, 'error while sending events', error);
                deferred.reject(error);
            });
        return deferred.promise;
    };

    var createSyncStartEvent = function () {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['start'],
            'properties': {}
        };
    };

    var createSyncErrorEvent = function (code) {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['error'],
            'properties': {
                code: code,
                reauth: process.env.GITHUB_INT_CONTEXT_URI + '/reauth'
            }
        };
    };

    var createSyncCompleteEvent = function () {
        return {
            'dateTime': moment().toISOString(),
            'objectTags': ['1self', 'integration', 'sync'],
            'actionTags': ['complete'],
            'properties': {}
        };
    };

    var getGithubCommitEvents = function (filteredEvents, userInfo) {
        logger.logDebug(userInfo.githubUsername, 'getting commit events for push events, [event count]', filteredEvents.length);
        var deferred = Q.defer();

        var commitObjects = [];

        var userEmailParts = /(.*?)(\+.*?)?(@.*)/g.exec(userInfo.email);
        var userEmail = userEmailParts ? userEmailParts[1] + userEmailParts[3] : null;

        logger.logDebug(userInfo.githubUsername, 'flattening commits');
        logger.logDebug(userInfo.githubUsername, 'removing push email alias, [original, unaliased]', [userInfo.email, userEmail]);

        _.each(filteredEvents, function (event) {
            _.each(event.payload.commits, function (commit) {
                var commitReq = {
                    url: commit.url,
                    pushId: event.payload.push_id,
                    repo: event.repo.name
                };

                commitReq.committerIsAuthor = true;

                if(userEmail){
                    var commitEmailParts = /(.*?)(\+.*?)?(@.*)/g.exec(commit.author.email);
                    if(commitEmailParts.length === 4){
                        var commitEmail = commitEmailParts[1] + commitEmailParts[3];
                        commitReq.committerIsAuthor = commitEmail === userEmail;
                    }
                }

                logger.logDebug(userInfo.githubUsername, 'commit req', commitReq);
                commitObjects.push(commitReq);
            });
        });

        logger.logDebug(userInfo.githubUsername, 'commit have been flattened, [commits]', commitObjects);

        // the delay is in there as the github api is returning an error when hit with lots of requests
        // quickly.
        var getCommitPromise = function (commitObject, delay) {
            var deferred = Q.defer();
            var url = commitObject.url + '?access_token=' + userInfo.accessToken;
            var options = {
                url: url,
                headers: {
                    'User-Agent': '1self'
                }
            };

            setTimeout(function(){
                logger.logDebug(userInfo.githubUsername, [options.url, 'requesting commit, [options, delay]'].join(': '), [options, delay]);
                request(options, function (err, res, body) {
                    if (!err) {
                        logger.logDebug(userInfo.githubUsername, [options.url, 'request successful'].join(': '));
                        var commit = JSON.parse(body);
                        commit.pushId = commitObject.pushId;
                        commit.repo = commitObject.repo;
                        commit.committerIsAuthor = commitObject.committerIsAuthor;
                        deferred.resolve(commit);
                    }
                    else {
                        logger.logDebug(userInfo.githubUsername, [options.url, 'request failed, [error]'].join(': '), err);
                        deferred.reject(err);
                    }
                }).end();
            },
            delay);
            return deferred.promise;
        };

        var promiseArray = [];

        _.map(commitObjects, function (commitObject, i) {
                promiseArray.push(getCommitPromise(commitObject, i * 100));
        });

        Q.all(promiseArray).then(function (commitEvents) {
            logger.logDebug(userInfo.githubUsername, 'all commit events retrieved');
            var events = filteredEvents.concat(commitEvents);
            deferred.resolve(events);
        }).catch(function (error) {
            logger.logError(userInfo.githubUsername, 'Error occurred :: getGithubCommitEvents', error);
        });

        return deferred.promise;
    };

    this.sendGithubEvents = function (userInfo, streamInfo, appUri) {
        logger.logInfo(userInfo.githubUsername, 'starting sync, sending start sync event, [appUri]', [appUri]);
        var syncStartEvent = createSyncStartEvent();

        qdService.sendEvent(syncStartEvent, streamInfo, appUri)
            .then(function(){
                logger.logInfo(userInfo.githubUsername, 'testing token validity');
                logger.logInfo(userInfo.githubUsername, userInfo);
                return self.checkToken(userInfo, request, logger);
            })
            .then(function () {
                logger.logInfo(userInfo.githubUsername, 'fetching events from github api', []);
                return fetchGithubPushEvents(userInfo);
            })
            .then(function (events) {
                logger.logInfo(userInfo.githubUsername, 'filtering events to include only pushes, [event count]', [events.length]);
                return filterEventsToBeSent(userInfo, events, streamInfo.lastSyncDate);
            })
            .then(function (filteredEvents) {
                logger.logInfo(userInfo.githubUsername, 'getting the commit events for the pushes, [event count]', filteredEvents.length);
                return getGithubCommitEvents(filteredEvents, userInfo);
            })
            .then(function (filteredEvents){
                logger.logInfo(userInfo.githubUsername, 'converting events to 1self format, [event count]', filteredEvents.length);
                return convertEventsTo1SelfFormat(filteredEvents, userInfo.githubUsername);
            })
            .then(function (eventsToBeSent) {
                logger.logInfo(userInfo.githubUsername, 'sending the events to 1self, [event count]', eventsToBeSent.length);
                return sendEventsToQD(eventsToBeSent, streamInfo, appUri, userInfo);
            })
            .then(function () {
                logger.logInfo(userInfo.githubUsername, 'sending sync complete to 1self', []);
                var syncCompleteEvent = createSyncCompleteEvent();
                return qdService.sendEvent(syncCompleteEvent, streamInfo, appUri);
            })
            .then(function() {
                logger.logInfo(userInfo.githubUsername, 'finished sending events to 1self');
            })
            .catch(function (error) {
                logger.logError(userInfo.githubUsername, 'Error occurred :: sendGithubEvents', error);
                if(error.code === 401){
                    logger.logError(userInfo.githubUsername, 'sending error event');
                    var errorEvent = createSyncErrorEvent(error.code);
                    return qdService.sendEvent(errorEvent, streamInfo, appUri);
                }
            })
            .done() ;
    };

    this.setLogger = function(newLogger){
        logger = newLogger;
    };

};
<|endoftext|>


<commit_before>var models  = require('../models');
var express = require('express');
var router = express.Router();

/* GET users listing. */
router.get('/', function(req, res) {
  var is_authorized = false;
  var sess = req.session;
  if (sess.user_id) {
    is_authorized = true;
  } else {

  }

  res.render('notification', {
  });
});

module.exports = router;
<commit_msg>Created reading and updating functions for notifications<commit_after>var models  = require('../models');
var express = require('express');
var router = express.Router();

/* GET notifications listing. */
router.get('/', function(req, res) {
  var is_authorized = false;
  var sess = req.session;
  if (sess.user_id) {
    is_authorized = true;
  } else {

  }

  models.Notification.findAll({
  	where: {
      userId: sess.user_id
    },
    include: [models.Job]
  }).then(function(notifications) {
    res.render('notification', {
      title: 'Notifications',
      notifications: notifications
    });
  });
});

/* POST mark as read */
router.post('/:notification_id/read', function(req, res) {
  var sess = req.session;
  models.Notification.update({
    status: 1
  },{
    where: {
      id: req.params.notification_id
    }
  }).then(function(){
    res.redirect('/notification');
  });
});

module.exports = router;
<|endoftext|>


<commit_before>/*** Array ***/

Array.prototype.random = function() {
    return this[Math.floor((Math.random()*this.length))];
};

Array.prototype.each = function(fun) {
    for(var i=0;i<this.length;i++) {
        fun(this[i]);
    }
};

Array.prototype.collect = function(fun) {
    var collect = [];
    for(var i=0;i<this.length;i++) {
        collect.push(fun(this[i]));
    }
    return collect;
};

Array.prototype.include = function(value) {
    for(var i=0;i<this.length;i++) {
        if(this[i] == value) {
            return true;
        }
    }
    return false;
};

Array.prototype.sum = function() {
    var sum = 0;
    for(var i=0;i<this.length;i++) {
        sum += (parseFloat(this[i]) || 0);
    }
    return sum;
};

Array.prototype.allGroupings = function() {
    if (this.length == 0) {
        return [];  /* short-circuit the empty-array case */
    }
    var groupings = [];
    for(var n=1;n<=this.length;n++) {
        for(var i=0;i<(this.length-(n-1));i++) {
            groupings.push(this.slice(i, i+n));
        }
    }
    return groupings;
}

Array.prototype.uniq = function() {
    var hash = {}
    var result = [];
    this.each(function(item) {
        if(!hash.hasOwnProperty(item)){
            hash[item] = true;
            result.push(item);
        }
    });
    return result;
}

/*** String ***/

String.prototype.valMatch = function(regex, expLength) {
    var key = this.match(regex);
    if(key !== null && key.length == expLength) {
        return key;
    } else {
        return false;
    }
};

String.prototype.endsWith = function(needle) {
    return needle === this.slice(this.length - needle.length);
};

String.prototype.startsWith = function(needle) {
    return needle === this.slice(0, needle.length);
};

String.prototype.distance = function(s1, s2) {
    // Calculate Levenshtein distance between two strings
    //
    // version: 1109.2015
    // discuss at: http://phpjs.org/functions/levenshtein    // +            original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
    // +            bugfixed by: Onno Marsman
    // +             revised by: Andrea Giammarchi (http://webreflection.blogspot.com)
    // + reimplemented by: Brett Zamir (http://brett-zamir.me)
    // + reimplemented by: Alexander M Beedie    // *                example 1: levenshtein('Kevin van Zonneveld', 'Kevin van Sommeveld');
    // *                returns 1: 3
    if (s1 == s2) {
        return 0;
    }
    var s1_len = s1.length;
    var s2_len = s2.length;
    if (s1_len === 0) {
        return s2_len;    }
    if (s2_len === 0) {
        return s1_len;
    }
     // BEGIN STATIC
    var split = false;
    try {
        split = !('0')[0];
    } catch (e) {        split = true; // Earlier IE may not support access by string index
    }
    // END STATIC
    if (split) {
        s1 = s1.split('');        s2 = s2.split('');
    }

    var v0 = new Array(s1_len + 1);
    var v1 = new Array(s1_len + 1);
    var s1_idx = 0,
        s2_idx = 0,
        cost = 0;
    for (s1_idx = 0; s1_idx < s1_len + 1; s1_idx++) {        v0[s1_idx] = s1_idx;
    }
    var char_s1 = '',
        char_s2 = '';
    for (s2_idx = 1; s2_idx <= s2_len; s2_idx++) {        v1[0] = s2_idx;
        char_s2 = s2[s2_idx - 1];

        for (s1_idx = 0; s1_idx < s1_len; s1_idx++) {
            char_s1 = s1[s1_idx];            cost = (char_s1 == char_s2) ? 0 : 1;
            var m_min = v0[s1_idx + 1] + 1;
            var b = v1[s1_idx] + 1;
            var c = v0[s1_idx] + cost;
            if (b < m_min) {                m_min = b;
            }
            if (c < m_min) {
                m_min = c;
            }            v1[s1_idx + 1] = m_min;
        }
        var v_tmp = v0;
        v0 = v1;
        v1 = v_tmp;    }
    return v0[s1_len];
}

String.prototype.format = function() { // format takes either multiple indexed arguments, or a single object, whose keys/values will be used
    var targetStr = this;
    var replacements = [].splice.call(arguments, 0);
    if ((replacements.length === 1) && (typeof(replacements[0]) === 'object')) { // if we were passed a single object rather than multiple args
        replacements = replacements[0]; // use the object as source of replacements
    };
    for (key in replacements) {
        if (replacements.hasOwnProperty(key)) {
            var replacePattern = new RegExp("\\{"+key+"\\}", "g");
            targetStr = targetStr.replace(replacePattern, replacements[key]);
        };
    };
    return targetStr;
};

/*** Object ***/

Object.prototype.isFunction = function(obj) {
    return typeof(obj) === 'function';
};

Object.prototype.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
};

Object.prototype.withAll = function(fun) {
    for(key in this) {
        if(this.hasOwnProperty(key)){
            fun(key, this[key]);
        }
    }
};

Object.prototype.length = function() {
    var l = 0;
    for(key in this)
        if(this.hasOwnProperty(key))
            l++;
    return l;
}

/*** Integer ***/

Number.prototype.chanceIn = function(x, y) {
    var num = Math.floor(Math.random() * (y + 1)) / x;
    return num == 1;
};

/*** Regex ***/
RegExp.prototype.url_regex = function() {
    var reg = new RegExp(
       "^" +
       // protocol identifier
       "(?:(?:https?|ftp)://)" +
       // user:pass authentication
       "(?:\\S+(?::\\S*)?@)?" +
       "(?:" +
       // IP address exclusion
       // private & local networks
       "(?!10(?:\\.\\d{1,3}){3})" +
       "(?!127(?:\\.\\d{1,3}){3})" +
       "(?!169\\.254(?:\\.\\d{1,3}){2})" +
       "(?!192\\.168(?:\\.\\d{1,3}){2})" +
       "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
       // IP address dotted notation octets
       // excludes loopback network 0.0.0.0
       // excludes reserved space >= 224.0.0.0
       // excludes network & broacast addresses
       // (first & last IP address of each class)
       "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
       "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
       "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
       "|" +
       // host name
       "(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)" +
       // domain name
       "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
       // TLD identifier
       "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
       ")" +
       // port number
       "(?::\\d{2,5})?" +
       // resource path
        "(?:/[^\\s]*)?" +
        "$", "i"
    );
    return reg;
}
<commit_msg>remove withAll<commit_after>/*** Array ***/

Array.prototype.random = function() {
    return this[Math.floor((Math.random()*this.length))];
};

Array.prototype.each = function(fun) {
    for(var i=0;i<this.length;i++) {
        fun(this[i]);
    }
};

Array.prototype.collect = function(fun) {
    var collect = [];
    for(var i=0;i<this.length;i++) {
        collect.push(fun(this[i]));
    }
    return collect;
};

Array.prototype.include = function(value) {
    for(var i=0;i<this.length;i++) {
        if(this[i] == value) {
            return true;
        }
    }
    return false;
};

Array.prototype.sum = function() {
    var sum = 0;
    for(var i=0;i<this.length;i++) {
        sum += (parseFloat(this[i]) || 0);
    }
    return sum;
};

Array.prototype.allGroupings = function() {
    if (this.length == 0) {
        return [];  /* short-circuit the empty-array case */
    }
    var groupings = [];
    for(var n=1;n<=this.length;n++) {
        for(var i=0;i<(this.length-(n-1));i++) {
            groupings.push(this.slice(i, i+n));
        }
    }
    return groupings;
}

Array.prototype.uniq = function() {
    var hash = {}
    var result = [];
    this.each(function(item) {
        if(!hash.hasOwnProperty(item)){
            hash[item] = true;
            result.push(item);
        }
    });
    return result;
}

/*** String ***/

String.prototype.valMatch = function(regex, expLength) {
    var key = this.match(regex);
    if(key !== null && key.length == expLength) {
        return key;
    } else {
        return false;
    }
};

String.prototype.endsWith = function(needle) {
    return needle === this.slice(this.length - needle.length);
};

String.prototype.startsWith = function(needle) {
    return needle === this.slice(0, needle.length);
};

String.prototype.distance = function(s1, s2) {
    // Calculate Levenshtein distance between two strings
    //
    // version: 1109.2015
    // discuss at: http://phpjs.org/functions/levenshtein    // +            original by: Carlos R. L. Rodrigues (http://www.jsfromhell.com)
    // +            bugfixed by: Onno Marsman
    // +             revised by: Andrea Giammarchi (http://webreflection.blogspot.com)
    // + reimplemented by: Brett Zamir (http://brett-zamir.me)
    // + reimplemented by: Alexander M Beedie    // *                example 1: levenshtein('Kevin van Zonneveld', 'Kevin van Sommeveld');
    // *                returns 1: 3
    if (s1 == s2) {
        return 0;
    }
    var s1_len = s1.length;
    var s2_len = s2.length;
    if (s1_len === 0) {
        return s2_len;    }
    if (s2_len === 0) {
        return s1_len;
    }
     // BEGIN STATIC
    var split = false;
    try {
        split = !('0')[0];
    } catch (e) {        split = true; // Earlier IE may not support access by string index
    }
    // END STATIC
    if (split) {
        s1 = s1.split('');        s2 = s2.split('');
    }

    var v0 = new Array(s1_len + 1);
    var v1 = new Array(s1_len + 1);
    var s1_idx = 0,
        s2_idx = 0,
        cost = 0;
    for (s1_idx = 0; s1_idx < s1_len + 1; s1_idx++) {        v0[s1_idx] = s1_idx;
    }
    var char_s1 = '',
        char_s2 = '';
    for (s2_idx = 1; s2_idx <= s2_len; s2_idx++) {        v1[0] = s2_idx;
        char_s2 = s2[s2_idx - 1];

        for (s1_idx = 0; s1_idx < s1_len; s1_idx++) {
            char_s1 = s1[s1_idx];            cost = (char_s1 == char_s2) ? 0 : 1;
            var m_min = v0[s1_idx + 1] + 1;
            var b = v1[s1_idx] + 1;
            var c = v0[s1_idx] + cost;
            if (b < m_min) {                m_min = b;
            }
            if (c < m_min) {
                m_min = c;
            }            v1[s1_idx + 1] = m_min;
        }
        var v_tmp = v0;
        v0 = v1;
        v1 = v_tmp;    }
    return v0[s1_len];
}

String.prototype.format = function() { // format takes either multiple indexed arguments, or a single object, whose keys/values will be used
    var targetStr = this;
    var replacements = [].splice.call(arguments, 0);
    if ((replacements.length === 1) && (typeof(replacements[0]) === 'object')) { // if we were passed a single object rather than multiple args
        replacements = replacements[0]; // use the object as source of replacements
    };
    for (key in replacements) {
        if (replacements.hasOwnProperty(key)) {
            var replacePattern = new RegExp("\\{"+key+"\\}", "g");
            targetStr = targetStr.replace(replacePattern, replacements[key]);
        };
    };
    return targetStr;
};

/*** Object ***/

Object.prototype.isFunction = function(obj) {
    return typeof(obj) === 'function';
};

Object.prototype.isArray = function(obj) {
    return Object.prototype.toString.call(obj) === '[object Array]';
};

/*Object.prototype.withAll = function(fun) {
    for(key in this) {
        if(this.hasOwnProperty(key)){
            fun(key, this[key]);
        }
    }
};*/

Object.prototype.length = function() {
    var l = 0;
    for(key in this)
        if(this.hasOwnProperty(key))
            l++;
    return l;
}

/*** Integer ***/

Number.prototype.chanceIn = function(x, y) {
    var num = Math.floor(Math.random() * (y + 1)) / x;
    return num == 1;
};

/*** Regex ***/
RegExp.prototype.url_regex = function() {
    var reg = new RegExp(
       "^" +
       // protocol identifier
       "(?:(?:https?|ftp)://)" +
       // user:pass authentication
       "(?:\\S+(?::\\S*)?@)?" +
       "(?:" +
       // IP address exclusion
       // private & local networks
       "(?!10(?:\\.\\d{1,3}){3})" +
       "(?!127(?:\\.\\d{1,3}){3})" +
       "(?!169\\.254(?:\\.\\d{1,3}){2})" +
       "(?!192\\.168(?:\\.\\d{1,3}){2})" +
       "(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})" +
       // IP address dotted notation octets
       // excludes loopback network 0.0.0.0
       // excludes reserved space >= 224.0.0.0
       // excludes network & broacast addresses
       // (first & last IP address of each class)
       "(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])" +
       "(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}" +
       "(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))" +
       "|" +
       // host name
       "(?:(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)" +
       // domain name
       "(?:\\.(?:[a-z\\u00a1-\\uffff0-9]+-?)*[a-z\\u00a1-\\uffff0-9]+)*" +
       // TLD identifier
       "(?:\\.(?:[a-z\\u00a1-\\uffff]{2,}))" +
       ")" +
       // port number
       "(?::\\d{2,5})?" +
       // resource path
        "(?:/[^\\s]*)?" +
        "$", "i"
    );
    return reg;
}
<|endoftext|>


<commit_before>const
    fs = require('fs-extra'),
    Path = require('path'),
    Url = require('url'),
    {BrowserWindow} = require('electron');

var Window = {
    openWindows: {}, // Keeps track of all open BrowserWindow's
    availableWindows: {}, // Stores all available windows to work with as JSON

    Open: function(windowName, template, events) {
        var window = Window.availableWindows[windowName];
        if(!window) return false; // A window by the specified name does not exist

        // The window.path is relative to the /views directory, but we are not
        var viewPath = Path.join(__dirname, '..', 'views', window.path);

        // If the requested view does not exist, exit
        if(!fs.existsSync(viewPath)) {
            console.error('Error opening new window: could not find view', viewPath);
            return false;
        }

        // If the window is already open and multiple are not allowed,
        // do not open another window
        if(!window.allowMultiple && Window.openWindows[windowName]) {
            Window.openWindows[windowName].focus(); // Bring the opened window to front-view
            return false;
        }

        // Indicate if this view uses Handlebars
        const isHandlebars =
            window.path.endsWith('.hbs') ||
            window.path.endsWith('.handlebars') ||
            window.requiresTemplate || // window specifies it needs a template
            template; // if we provide a template to an HTML file

        // Otherwise we create a new window
        var windowOptions = window;
        if(windowOptions.parent) {
            windowOptions.parent = Window.openWindows[windowOptions.parent];
        }
        windowOptions.webPreferences = {
            // Set preload on all windows to run the global-script
            // so globals are available to every window via `globals` variable
            preload: Path.join(__dirname, '../preload.js')
        }

        var newWindow = new BrowserWindow(windowOptions); // Create a new window
        Window.openWindows[windowName] = newWindow; // Register the new window

        // Encode any template data in the POST body
        var addlData = {};
        if(isHandlebars && template) {
            addlData = {
                // Encode handlebars template in post data
                postData: [{
                    type: 'rawData',
                    bytes: Buffer.from(JSON.stringify(template))
                }],
                extraHeaders: 'Content-Type: application/x-www-form-urlencoded'
            };
        }

        // Load the window with the specified view
        newWindow.loadURL(
            Url.format({
                pathname: viewPath,
                protocol: (isHandlebars) ? 'hbs:' : 'file:',
                slashes: true
            }),
            addlData
        );

        // Always open dev tools
        newWindow.webContents.openDevTools();

        // Iterate over events and add a new one to the window for each
        if(events) {
            Object.keys(events).forEach((event) => {
                newWindow.on(event, () => {
                    events[event]();
                });
            });
        }

        // We always handle the closed event
        newWindow.on('closed', () => {
            delete Window.openWindows[windowName];
        });
    },

    SendMessage: function(windowName, eventName, data) {
        if(Window.openWindows[windowName]) {
            Window.openWindows[windowName].webContents.send(eventName, data);
        }
    },

    Broadcast: function(eventName, data) {
        console.log('[ Event ]', eventName);

        Object.keys(Window.openWindows).forEach((window) => {
            Window.openWindows[window].webContents.send(eventName, data);
        })
    }
}

function loadDefaultInputWindows() {
    var inputTypes = ['int', 'unknown'];

    inputTypes.forEach((type) => {
        var inputName = 'input' + (type[0].toUpperCase()) + type.substr(1);
        Window.availableWindows[inputName] = {
            "name": inputName,
            "path": "/input/" + type + ".html",
            "description": "",
            "width": 400,
            "height": 300,
            "parent": "objectEditor",
            "modal": true,
            "frame": false,
            "allowMultiple": false,
            "requiresTemplate": true
        };
    })
}

function loadWindowsFromDir() {
    var windowsPath = Path.resolve(__dirname, '..', 'windows'),
        windowManifests = fs.readdirSync(windowsPath);

    windowManifests.forEach((manifestPath) => {
        var manifest = fs.readJsonSync(Path.resolve(windowsPath, manifestPath));
        Window.availableWindows[manifest.name] = manifest;
    });
}

loadDefaultInputWindows();
loadWindowsFromDir();
console.log('Loaded ' + Object.keys(Window.availableWindows).length + ' windows');
module.exports = Window;
<commit_msg>Remove dev tools always opening on each window, as this is now implemented in app<commit_after>const
    fs = require('fs-extra'),
    Path = require('path'),
    Url = require('url'),
    {BrowserWindow} = require('electron');

var Window = {
    openWindows: {}, // Keeps track of all open BrowserWindow's
    availableWindows: {}, // Stores all available windows to work with as JSON

    Open: function(windowName, template, events) {
        var window = Window.availableWindows[windowName];
        if(!window) return false; // A window by the specified name does not exist

        // The window.path is relative to the /views directory, but we are not
        var viewPath = Path.join(__dirname, '..', 'views', window.path);

        // If the requested view does not exist, exit
        if(!fs.existsSync(viewPath)) {
            console.error('Error opening new window: could not find view', viewPath);
            return false;
        }

        // If the window is already open and multiple are not allowed,
        // do not open another window
        if(!window.allowMultiple && Window.openWindows[windowName]) {
            Window.openWindows[windowName].focus(); // Bring the opened window to front-view
            return false;
        }

        // Indicate if this view uses Handlebars
        const isHandlebars =
            window.path.endsWith('.hbs') ||
            window.path.endsWith('.handlebars') ||
            window.requiresTemplate || // window specifies it needs a template
            template; // if we provide a template to an HTML file

        // Otherwise we create a new window
        var windowOptions = window;
        if(windowOptions.parent) {
            windowOptions.parent = Window.openWindows[windowOptions.parent];
        }
        windowOptions.webPreferences = {
            // Set preload on all windows to run the global-script
            // so globals are available to every window via `globals` variable
            preload: Path.join(__dirname, '../preload.js')
        }

        var newWindow = new BrowserWindow(windowOptions); // Create a new window
        Window.openWindows[windowName] = newWindow; // Register the new window

        // Encode any template data in the POST body
        var addlData = {};
        if(isHandlebars && template) {
            addlData = {
                // Encode handlebars template in post data
                postData: [{
                    type: 'rawData',
                    bytes: Buffer.from(JSON.stringify(template))
                }],
                extraHeaders: 'Content-Type: application/x-www-form-urlencoded'
            };
        }

        // Load the window with the specified view
        newWindow.loadURL(
            Url.format({
                pathname: viewPath,
                protocol: (isHandlebars) ? 'hbs:' : 'file:',
                slashes: true
            }),
            addlData
        );

        // Iterate over events and add a new one to the window for each
        if(events) {
            Object.keys(events).forEach((event) => {
                newWindow.on(event, () => {
                    events[event]();
                });
            });
        }

        // We always handle the closed event
        newWindow.on('closed', () => {
            delete Window.openWindows[windowName];
        });
    },

    SendMessage: function(windowName, eventName, data) {
        if(Window.openWindows[windowName]) {
            Window.openWindows[windowName].webContents.send(eventName, data);
        }
    },

    Broadcast: function(eventName, data) {
        console.log('[ Event ]', eventName);

        Object.keys(Window.openWindows).forEach((window) => {
            Window.openWindows[window].webContents.send(eventName, data);
        })
    }
}

function loadDefaultInputWindows() {
    var inputTypes = ['int', 'unknown'];

    inputTypes.forEach((type) => {
        var inputName = 'input' + (type[0].toUpperCase()) + type.substr(1);
        Window.availableWindows[inputName] = {
            "name": inputName,
            "path": "/input/" + type + ".html",
            "description": "",
            "width": 400,
            "height": 300,
            "parent": "objectEditor",
            "modal": true,
            "frame": false,
            "allowMultiple": false,
            "requiresTemplate": true
        };
    })
}

function loadWindowsFromDir() {
    var windowsPath = Path.resolve(__dirname, '..', 'windows'),
        windowManifests = fs.readdirSync(windowsPath);

    windowManifests.forEach((manifestPath) => {
        var manifest = fs.readJsonSync(Path.resolve(windowsPath, manifestPath));
        Window.availableWindows[manifest.name] = manifest;
    });
}

loadDefaultInputWindows();
loadWindowsFromDir();
console.log('Loaded ' + Object.keys(Window.availableWindows).length + ' windows');
module.exports = Window;
<|endoftext|>


<commit_before>/*
 *
 */

// Is ace a psuedo global? i.e. as should be loaded before this file is includes
// This file should be included before the js file in which your editor is defined
var ace_snippets = function(editor, session, mode, snippetText) {
	ace.require('ace/ext/language_tools');
	editor.setOptions({
		enableBasicAutocompletion: true,
		enableSnippets: true
	});

	var snippetManager = require("ace/snippets").snippetManager;

	var id = session.$mode.$id || "";
	var m = snippetManager.files[id];

	m.scope = mode;
	m.snippetText = snippetText;
	m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
	snippetManager.register(m.snippets, m.scope);
};

/* You should include a string such as this to overwrite the default snippets
 * This can be done either in the file you define your editor in or in another file and
 * then included in a script tag before you the file in which are defining your editor
 */

var eol = '\n';

// If you go this, be sure to include the eol newline character
var exampleSnippetText1 = [
	"snippet test",
	"	var test = function() {",
	"		return \"test\"",
	"	}",
	""
].join(eol);

// OR

var exampleSnippetText2 = "snippet test\n\
	var test = function() {\n\
		return \"test\"\n\
	}\n";

/*
 *  Custom snippet text strings that you can use in your implementation
 *  To use more than one, simple concatinate them together
 *  i.e. var mySnippetText = JsExtensionSnippetText + angularSnippetText + yourCustomSnippetText
 */

var JsExtensionSnippetText = [
	"snippet log",
	"	console.log(${1:})",
	""
].join(eol);

var angularSnippetText = [
	"snippet angular",
	"	angular.module(\"${1:modularName}\", [])",
	"snippet service",
	"	${1:module}.service(\"${2:ServiceName}\", [${3:$http}, function(${3:$http}) {",
	"		${4:Define service here}",
	"	}])",
	"snippet factory",
	"	${1:myModule}.factory('${2:myFactory}', [\"${3:$http}\"], function(${3:$http}) {",
	"		return {",
	"			${4:Enter business logic here}",
	"		}",
	"	});",
	"snippet controller",
	"	${1:myModule}.controller(\"${2:ControllerName}\", [$scope, function($scope) {",
	"		// ${3:Enter business logic here}",
	"	}]);",
	"snippet directive",
	"	${1:myModule}.directive(\"${2:DirectiveName}\", [$dep, function($dep) {",
	"		// ${3:Enter business logic here}",
	"	}])",
	"snippet constant",
	"	${1:myModule}.constant({\"key\", \"${CONSTANT_VALUE}\"})",
	"snippet config",
	"	${1:module}.config(function($routeProvider) {",
	"		$routeProvider",
	"			.when(\"/\", {",
	"				controller: ${2:MyController}",
	"				templateUrl: ${3:url}",
	"			}",
	"			.otherwise({ redirectTo: \"/\" })",
	"	});",
	"snippet when",
	"	.when(\"/\", {",
	"		controller: ${1:MyController}",
	"		templateUrl: ${2:url}",
	"	}",
	""
].join(eol);

var ejsSnippetText = [
	"snippet %for",
	"	<% for(var i = 0; i < ${1:obj}.length; i++) { %>",
	"		${1:obj}[i]",
	"	<% } %>",
	"snippet %forIn",
	"	<% for(var ${1:item} in ${2:someObj}) { %>",
	"		${2:someObj}[${1:item}]",
	"	<% } %>",
	"snippet %forIn",
	"	<% if(${1:condition == ${2:condition}) { %>",
	"		${3:expression}",
	"	<% } %>",
	"snippet %include",
	"<% include ${1:file} %>",
	""
].join(eol);

<commit_msg>Fixing bugs with built in snippets<commit_after>/*
 *
 */

// Is ace a psuedo global? i.e. as should be loaded before this file is includes
// This file should be included before the js file in which your editor is defined
var ace_snippets = function(editor, session, mode, snippetText) {
	ace.require('ace/ext/language_tools');
	editor.setOptions({
		enableBasicAutocompletion: true,
		enableSnippets: true
	});

	var snippetManager = require("ace/snippets").snippetManager;

	var id = session.$mode.$id || "";
	var m = snippetManager.files[id];

	m.scope = mode;
	m.snippetText = snippetText;
	m.snippets = snippetManager.parseSnippetFile(m.snippetText, m.scope);
	snippetManager.register(m.snippets, m.scope);
};

/* You should include a string such as this to overwrite the default snippets
 * This can be done either in the file you define your editor in or in another file and
 * then included in a script tag before you the file in which are defining your editor
 */

var eol = '\n';

// If you go this, be sure to include the eol newline character
var exampleSnippetText1 = [
	"snippet test",
	"	var test = function() {",
	"		return \"test\"",
	"	}",
	""
].join(eol);

// OR

var exampleSnippetText2 = "snippet test\n\
	var test = function() {\n\
		return \"test\"\n\
	}\n";

/*
 *  Custom snippet text strings that you can use in your implementation
 *  To use more than one, simple concatinate them together
 *  i.e. var mySnippetText = JsExtensionSnippetText + angularSnippetText + yourCustomSnippetText
 */

var JsExtensionSnippetText = [
	"snippet log",
	"	console.log(\"${1:}\")",
	""
].join(eol);

var angularSnippetText = [
	"snippet angular",
	"	angular.module(\"${1:modularName}\", [])",
	"snippet service",
	"	${1:module}.service(\"${2:ServiceName}\", [${3:\\$http}, function(${3:\\$http}) {",
	"		${4:Define service here}",
	"	}])",
	"snippet factory",
	"	${1:myModule}.factory('${2:myFactory}', [\"${3:\\$http}\"], function(${3:\\$http}) {",
	"		return {",
	"			${4:Enter business logic here}",
	"		}",
	"	});",
	"snippet controller",
	"	${1:myModule}.controller(\"${2:ControllerName}\", [\"\\$scope\", function(\\$scope) {",
	"		// ${3:Enter business logic here}",
	"	}]);",
	"snippet directive",
	"	${1:myModule}.directive(\"${2:DirectiveName}\", [\"${3:dep}\", function(${3:dep}) {",
	"		// ${4:Enter business logic here}",
	"	}])",
	"snippet constant",
	"	${1:myModule}.constant({\"key\", \"${2:value}\"})",
	"snippet config",
	"	${1:module}.config(function(\\$routeProvider) {",
	"		\\$routeProvider",
	"			.when(\"/\", {",
	"				controller: ${2:MyController},",
	"				templateUrl: ${3:url}",
	"			}",
	"			.otherwise({ redirectTo: \"/\" })",
	"	});",
	"snippet when",
	"	.when(\"/\", {",
	"		controller: ${1:MyController}",
	"		templateUrl: ${2:url}",
	"	}",
	""
].join(eol);

var ejsSnippetText = [
	"snippet efor",
	"	<% for(var i = 0; i < ${1:obj}.length; i++) { %>",
	"		${1:obj}[i]",
	"	<% } %>",
	"snippet eforin",
	"	<% for(var ${1:item} in ${2:someObj}) { %>",
	"		${2:someObj}[${1:item}]",
	"	<% } %>",
	"snippet eif",
	"	<% if(${1:condition} == ${2:condition}) { %>",
	"		${3:expression}",
	"	<% } %>",
	"snippet einclude",
	"	<% include ${1:file} %>",
	""
].join(eol);<|endoftext|>


<commit_before>/**
 * @fileOverview the interaction when geom was actived
 * @author sima.zhang
 */
const Util = require('../../util');
const FIELD_ORIGIN = '_origin';

function isSameShape(shape1, shape2) {
  if (Util.isNil(shape1) || Util.isNil(shape2)) {
    return false;
  }
  const shape1Origin = shape1.get('origin');
  const shape2Origin = shape2.get('origin');
  return Util.isEqual(shape1Origin, shape2Origin);
}

function isChange(preShapes, shapes) {
  if (!preShapes) {
    return true;
  }

  if (preShapes.length !== shapes.length) {
    return true;
  }

  let rst = false;
  Util.each(shapes, (shape, index) => {
    if (!isSameShape(shape, preShapes[index])) {
      rst = true;
      return false;
    }
  });
  return rst;
}

function getOriginAttrs(activeCfg, shape) {
  const originAttrs = {};
  Util.each(activeCfg, function(v, k) {
    let originValue = shape.__attrs[k];
    if (Util.isArray(originValue)) {
      originValue = Util.cloneDeep(originValue);// 缓存原来的属性，由于 __attrs.matrix 是数组，所以此处需要深度复制
    }
    originAttrs[k] = originValue;
  });
  return originAttrs;
}

const ActiveMixin = {
  _isAllowActive() {
    const allowActive = this.get('allowActive');
    if (Util.isNil(allowActive)) { // 用户未设置，使用默认的策略
      const view = this.get('view');
      const isShareTooltip = this.isShareTooltip();
      const options = view.get('options');
      // 默认情况下，tooltip 关闭或者 tooltip 模式为 shared === false 的时候允许 active
      if (options.tooltip === false || !isShareTooltip) {
        return true;
      }
    } else {
      return allowActive;
    }

    return false;
  },
  _onMouseenter(ev) {
    const self = this;
    const shape = ev.shape;
    const shapeContainer = self.get('shapeContainer');
    if (shape && shapeContainer.contain(shape) && self._isAllowActive()) { // shape.get('animating')
      self.setShapesActived(shape);
    }
  },
  _onMouseleave() {
    const self = this;
    const view = self.get('view');
    const canvas = view.get('canvas');
    if (self.get('activeShapes')) {
      self.clearActivedShapes();
      canvas.draw();
    }
  },
  _bindActiveAction() {
    const self = this;
    const view = self.get('view');
    const type = self.get('type');
    view.on(type + ':mouseenter', Util.wrapBehavior(self, '_onMouseenter'));
    view.on(type + ':mouseleave', Util.wrapBehavior(self, '_onMouseleave'));
  },
  _offActiveAction() {
    const self = this;
    const view = self.get('view');
    const type = self.get('type');
    view.off(type + ':mouseenter', Util.getWrapBehavior(self, '_onMouseenter'));
    view.off(type + ':mouseleave', Util.getWrapBehavior(self, '_onMouseleave'));
  },
  _setActiveShape(shape) {
    const self = this;
    const activedOptions = self.get('activedOptions') || {};
    const shapeData = shape.get('origin');
    let shapeName = shapeData.shape || self.getDefaultValue('shape');
    if (Util.isArray(shapeName)) {
      shapeName = shapeName[0];
    }
    const shapeFactory = self.get('shapeFactory');
    const shapeCfg = Util.mix({}, shape.__attrs, {
      origin: shapeData
    });
    const activeCfg = shapeFactory.getActiveCfg(shapeName, shapeCfg);
    if (activedOptions.style) {
      Util.mix(activeCfg, activedOptions.style);
    }
    const originAttrs = getOriginAttrs(activeCfg, shape);
    shape.setSilent('_originAttrs', originAttrs);
    if (activedOptions.animate) {
      shape.animate(activeCfg, 300);
    } else {
      // Util.mix(shape.__attrs, activeCfg);
      shape.attr(activeCfg);
    }
    shape.set('zIndex', 1); // 提前
  },
  setShapesActived(shapes) {
    const self = this;
    if (!Util.isArray(shapes)) {
      shapes = [ shapes ];
    }
    const preShapes = self.get('activeShapes'); // 获取上次被激活的 shapes
    if (!isChange(preShapes, shapes)) {
      return;
    }
    const view = self.get('view');
    const canvas = view.get('canvas');
    const shapeContainer = self.get('shapeContainer');
    const activedOptions = self.get('activedOptions');
    if (activedOptions && activedOptions.highlight) {
      // 上次的动画未完成，所以要停止掉动画
      Util.each(shapes, shape => {
        if (shape.get('animating')) {
          shape.stopAnimate();
        }
      });
      self.highlightShapes(shapes);
    } else {
      if (preShapes) {
        self.clearActivedShapes(); // 先清除激活元素
      }

      Util.each(shapes, shape => {
        if (shape.get('animating')) {
          shape.stopAnimate();
        }
        if (shape.get('visible') && !shape.get('selected')) {
          self._setActiveShape(shape);
        }
      });
    }
    self.set('activeShapes', shapes);
    shapeContainer.sort();
    canvas.draw();
  },
  clearActivedShapes() {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const activedOptions = self.get('activedOptions');
    const activeAnimate = activedOptions && activedOptions.animate;
    if (shapeContainer && !shapeContainer.get('destroyed')) {
      const activeShapes = self.get('activeShapes');
      Util.each(activeShapes, activeShape => {
        if (!activeShape.get('selected')) {
          const originAttrs = activeShape.get('_originAttrs');
          if (activeAnimate) {
            activeShape.stopAnimate();
            activeShape.animate(originAttrs, 300);
          } else {
            activeShape.attr(originAttrs);
          }
          activeShape.setZIndex(0);
          activeShape.set('_originAttrs', null);
        }
      });
      const preHighlightShapes = self.get('preHighlightShapes');
      if (preHighlightShapes) {
        const shapes = shapeContainer.get('children');
        Util.each(shapes, shape => {
          if (!shape.get('selected')) {
            const originAttrs = shape.get('_originAttrs');
            if (originAttrs) {
              if (activeAnimate) {
                shape.stopAnimate();
                shape.animate(originAttrs, 300);
              } else {
                shape.attr(originAttrs);
              }
              shape.setZIndex(0);
              shape.set('_originAttrs', null);
            }
          }
        });
      }
      // 恢复原来排序
      const children = shapeContainer.get('children');
      children.sort((obj1, obj2) => {
        return obj1._INDEX - obj2._INDEX;
      });

      self.set('activeShapes', null);
      self.set('preHighlightShapes', null);
    }
  },
  getGroupShapesByPoint(point) {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const activeShapes = [];
    if (shapeContainer) {
      const xField = self.getXScale().field;
      const shapes = self.getShapes();
      const originObj = self._getOriginByPoint(point);
      Util.each(shapes, shape => {
        const origin = shape.get('origin');
        if (shape.get('visible') && origin) { // 有可能不是图形，而是label文本，所以判断一下
          const shapeXValue = origin[FIELD_ORIGIN][xField];
          if (shapeXValue === originObj[xField]) {
            activeShapes.push(shape);
          }
        }
      });
    }
    return activeShapes;
  },
  getSingleShapeByPoint(point) {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const canvas = shapeContainer.get('canvas');
    const pixelRatio = canvas.get('pixelRatio');
    let result;
    if (shapeContainer) {
      result = shapeContainer.getShape(point.x * pixelRatio, point.y * pixelRatio);
    }

    if (result && result.get('origin')) {
      return result;
    }
  },
  highlightShapes(highlightShapes, highlightCfg) {
    const self = this;
    if (!Util.isArray(highlightShapes)) {
      highlightShapes = [ highlightShapes ];
    }

    const preHighlightShapes = self.get('activeShapes'); // 获取上次被激活的 shapes
    if (!isChange(preHighlightShapes, highlightShapes)) {
      return;
    }
    if (preHighlightShapes) {
      self.clearActivedShapes();
    }

    const shapes = self.getShapes();
    const activedOptions = self.get('activedOptions');
    const activeAnimate = activedOptions && activedOptions.animate;
    const activeStyle = activedOptions && activedOptions.style;

    Util.each(shapes, shape => {
      const changeAttrs = {};
      shape.stopAnimate();
      if (Util.indexOf(highlightShapes, shape) !== -1) {
        Util.mix(changeAttrs, activeStyle, highlightCfg);
        // shape.__attrs = Util.mix({}, shape.get('_originAttrs'), highlightCfg);
        shape.setZIndex(1); // 提前
      } else {
        Util.mix(changeAttrs, {
          fillOpacity: 0.3
        });
        shape.setZIndex(0);
      }
      const originAttrs = getOriginAttrs(changeAttrs, shape);
      shape.setSilent('_originAttrs', originAttrs);
      if (activeAnimate) {
        shape.animate(changeAttrs, 300);
      } else {
        shape.attr(changeAttrs);
      }
    });
    self.set('preHighlightShapes', highlightShapes);
    self.set('activeShapes', highlightShapes);
  }
};

module.exports = ActiveMixin;
<commit_msg>修复线图active高亮不生效的bug<commit_after>/**
 * @fileOverview the interaction when geom was actived
 * @author sima.zhang
 */
const Util = require('../../util');
const FIELD_ORIGIN = '_origin';

function isSameShape(shape1, shape2) {
  if (Util.isNil(shape1) || Util.isNil(shape2)) {
    return false;
  }
  const shape1Origin = shape1.get('origin');
  const shape2Origin = shape2.get('origin');
  return Util.isEqual(shape1Origin, shape2Origin);
}

function isChange(preShapes, shapes) {
  if (!preShapes) {
    return true;
  }

  if (preShapes.length !== shapes.length) {
    return true;
  }

  let rst = false;
  Util.each(shapes, (shape, index) => {
    if (!isSameShape(shape, preShapes[index])) {
      rst = true;
      return false;
    }
  });
  return rst;
}

function getOriginAttrs(activeCfg, shape) {
  const originAttrs = {};
  Util.each(activeCfg, function(v, k) {
    let originValue = shape.__attrs[k];
    if (Util.isArray(originValue)) {
      originValue = Util.cloneDeep(originValue);// 缓存原来的属性，由于 __attrs.matrix 是数组，所以此处需要深度复制
    }
    originAttrs[k] = originValue;
  });
  return originAttrs;
}

const ActiveMixin = {
  _isAllowActive() {
    const allowActive = this.get('allowActive');
    if (Util.isNil(allowActive)) { // 用户未设置，使用默认的策略
      const view = this.get('view');
      const isShareTooltip = this.isShareTooltip();
      const options = view.get('options');
      // 默认情况下，tooltip 关闭或者 tooltip 模式为 shared === false 的时候允许 active
      if (options.tooltip === false || !isShareTooltip) {
        return true;
      }
    } else {
      return allowActive;
    }

    return false;
  },
  _onMouseenter(ev) {
    const self = this;
    const shape = ev.shape;
    const shapeContainer = self.get('shapeContainer');
    if (shape && shapeContainer.contain(shape) && self._isAllowActive()) { // shape.get('animating')
      self.setShapesActived(shape);
    }
  },
  _onMouseleave() {
    const self = this;
    const view = self.get('view');
    const canvas = view.get('canvas');
    if (self.get('activeShapes')) {
      self.clearActivedShapes();
      canvas.draw();
    }
  },
  _bindActiveAction() {
    const self = this;
    const view = self.get('view');
    const type = self.get('type');
    view.on(type + ':mouseenter', Util.wrapBehavior(self, '_onMouseenter'));
    view.on(type + ':mouseleave', Util.wrapBehavior(self, '_onMouseleave'));
  },
  _offActiveAction() {
    const self = this;
    const view = self.get('view');
    const type = self.get('type');
    view.off(type + ':mouseenter', Util.getWrapBehavior(self, '_onMouseenter'));
    view.off(type + ':mouseleave', Util.getWrapBehavior(self, '_onMouseleave'));
  },
  _setActiveShape(shape) {
    const self = this;
    const activedOptions = self.get('activedOptions') || {};
    const shapeData = shape.get('origin');
    let shapeName = shapeData.shape || self.getDefaultValue('shape');
    if (Util.isArray(shapeName)) {
      shapeName = shapeName[0];
    }
    const shapeFactory = self.get('shapeFactory');
    const shapeCfg = Util.mix({}, shape.__attrs, {
      origin: shapeData
    });
    const activeCfg = shapeFactory.getActiveCfg(shapeName, shapeCfg);
    if (activedOptions.style) {
      Util.mix(activeCfg, activedOptions.style);
    }
    const originAttrs = getOriginAttrs(activeCfg, shape);
    shape.setSilent('_originAttrs', originAttrs);
    if (activedOptions.animate) {
      shape.animate(activeCfg, 300);
    } else {
      // Util.mix(shape.__attrs, activeCfg);
      shape.attr(activeCfg);
    }
    shape.set('zIndex', 1); // 提前
  },
  setShapesActived(shapes) {
    const self = this;
    if (!Util.isArray(shapes)) {
      shapes = [ shapes ];
    }
    const preShapes = self.get('activeShapes'); // 获取上次被激活的 shapes
    if (!isChange(preShapes, shapes)) {
      return;
    }
    const view = self.get('view');
    const canvas = view.get('canvas');
    const shapeContainer = self.get('shapeContainer');
    const activedOptions = self.get('activedOptions');
    if (activedOptions && activedOptions.highlight) {
      // 上次的动画未完成，所以要停止掉动画
      Util.each(shapes, shape => {
        if (shape.get('animating')) {
          shape.stopAnimate();
        }
      });
      self.highlightShapes(shapes);
    } else {
      if (preShapes) {
        self.clearActivedShapes(); // 先清除激活元素
      }

      Util.each(shapes, shape => {
        if (shape.get('animating')) {
          shape.stopAnimate();
        }
        if (shape.get('visible') && !shape.get('selected')) {
          self._setActiveShape(shape);
        }
      });
    }
    self.set('activeShapes', shapes);
    shapeContainer.sort();
    canvas.draw();
  },
  clearActivedShapes() {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const activedOptions = self.get('activedOptions');
    const activeAnimate = activedOptions && activedOptions.animate;
    if (shapeContainer && !shapeContainer.get('destroyed')) {
      const activeShapes = self.get('activeShapes');
      Util.each(activeShapes, activeShape => {
        if (!activeShape.get('selected')) {
          const originAttrs = activeShape.get('_originAttrs');
          if (activeAnimate) {
            activeShape.stopAnimate();
            activeShape.animate(originAttrs, 300);
          } else {
            activeShape.attr(originAttrs);
          }
          activeShape.setZIndex(0);
          activeShape.set('_originAttrs', null);
        }
      });
      const preHighlightShapes = self.get('preHighlightShapes');
      if (preHighlightShapes) {
        const shapes = shapeContainer.get('children');
        Util.each(shapes, shape => {
          if (!shape.get('selected')) {
            const originAttrs = shape.get('_originAttrs');
            if (originAttrs) {
              if (activeAnimate) {
                shape.stopAnimate();
                shape.animate(originAttrs, 300);
              } else {
                shape.attr(originAttrs);
              }
              shape.setZIndex(0);
              shape.set('_originAttrs', null);
            }
          }
        });
      }
      // 恢复原来排序
      const children = shapeContainer.get('children');
      children.sort((obj1, obj2) => {
        return obj1._INDEX - obj2._INDEX;
      });

      self.set('activeShapes', null);
      self.set('preHighlightShapes', null);
    }
  },
  getGroupShapesByPoint(point) {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const activeShapes = [];
    if (shapeContainer) {
      const xField = self.getXScale().field;
      const shapes = self.getShapes();
      const originObj = self._getOriginByPoint(point);
      Util.each(shapes, shape => {
        const origin = shape.get('origin');
        if (shape.get('visible') && origin) { // 有可能不是图形，而是label文本，所以判断一下
          const shapeXValue = origin[FIELD_ORIGIN][xField];
          if (shapeXValue === originObj[xField]) {
            activeShapes.push(shape);
          }
        }
      });
    }
    return activeShapes;
  },
  getSingleShapeByPoint(point) {
    const self = this;
    const shapeContainer = self.get('shapeContainer');
    const canvas = shapeContainer.get('canvas');
    const pixelRatio = canvas.get('pixelRatio');
    let result;
    if (shapeContainer) {
      result = shapeContainer.getShape(point.x * pixelRatio, point.y * pixelRatio);
    }

    if (result && result.get('origin')) {
      return result;
    }
  },
  highlightShapes(highlightShapes, highlightCfg) {
    const self = this;
    if (!Util.isArray(highlightShapes)) {
      highlightShapes = [ highlightShapes ];
    }

    const preHighlightShapes = self.get('activeShapes'); // 获取上次被激活的 shapes
    if (!isChange(preHighlightShapes, highlightShapes)) {
      return;
    }
    if (preHighlightShapes) {
      self.clearActivedShapes();
    }

    const shapes = self.getShapes();
    const activedOptions = self.get('activedOptions');
    const activeAnimate = activedOptions && activedOptions.animate;
    const activeStyle = activedOptions && activedOptions.style;

    Util.each(shapes, shape => {
      const changeAttrs = {};
      shape.stopAnimate();
      if (Util.indexOf(highlightShapes, shape) !== -1) {
        Util.mix(changeAttrs, activeStyle, highlightCfg);
        // shape.__attrs = Util.mix({}, shape.get('_originAttrs'), highlightCfg);
        shape.setZIndex(1); // 提前
      } else {
        Util.mix(changeAttrs, {
          // @2018-07-11 by blue.lb 由于线图只有stoke，fillOpacity不生效，最好还是直接改成整个图形透明度opacity
          opacity: 0.3
        });
        shape.setZIndex(0);
      }
      const originAttrs = getOriginAttrs(changeAttrs, shape);
      shape.setSilent('_originAttrs', originAttrs);
      if (activeAnimate) {
        shape.animate(changeAttrs, 300);
      } else {
        shape.attr(changeAttrs);
      }
    });
    self.set('preHighlightShapes', highlightShapes);
    self.set('activeShapes', highlightShapes);
  }
};

module.exports = ActiveMixin;
<|endoftext|>