<commit_before>var GitHubAPI = require('github'),
    _ = require('underscore');

var github = new GitHubAPI({
    version: "3.0.0",
    protocol: "https",
    timeout: 5000
});

function getRepoInformation(username, reponame, cb) {
    github.repos.get({
        user: username,
        repo: reponame
    }, function(err, res) {
        if (err) {
            cb("Github response is dicked");
        } else {
            var name = res.name,
                description = res.description,
                language = res.language,
                forks = "Forks: " + res.forks_count;
            if (!language)
                language = "";
            else
                language = "| " + language;
            if (description.length > 60)
                description = description.substr(0, 40);

            cb(name, '| ', description, language, '| ', forks);
        }
    });
}

var githubURLRegexes = [
    {
        name: "User",
        regex: /github\.com\/(\w+)\/?/,
        getMessage: function(username, cb) {
            github.user.getFrom({
                user: username
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var followers = res.followers,
                        following = res.following,
                        publicRepose = res.public_repos,
                        company = res.company;
                        if (!company) company = "";
                        else company = "Works for " + company + " |";

                    cb(username + ":", company, "Followers:",
                        followers, "| Following:", following);
                }
            });
        }
    },
    {
        name: "Repo",
        regex: /github\.com\/(\w+)\/((?:\w|-)+)\/?/,
        getMessage: getRepoInformation
    },
    {
        name: "Commit",
        regex: /github\.com\/(\w+)\/((?:\w|-)+)\/commit\/(\w+)\/?/,
        getMessage: function(username, reponame, commit, cb) {
            github.repos.getCommit({
                user: username,
                repo: reponame,
                sha: commit
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var committer = res.committer.login,
                        message = res.commit.message;
                    // Extract first line of commit message
                    message = /.*/.exec(message);
                    if (message) message = message[0];
                    else message = "";
                    if (message.length > 50) message = message.substr(0, 50);

                    cb("Commit to", reponame, "by", committer + ":", message);
                }
            });
        }
    },
    {
        name: "Issue",
        regex: /github\.com\/(\w+)\/((?:\w|-)+)\/issues\/(\d+)\/?/,
        getMessage: function(username, reponame, issue, cb) {
            github.issues.getRepoIssue({
                user: username,
                repo: reponame,
                number: issue
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var title = res.title,
                        state = res.state;
                    cb("Issue for", reponame + ":", title, "|", state);
                }
            });
        }
    },
    {
        name: "IO Page",
        regex: /\/\/(\w+)\.github\.io\/((?:\w|-)+)\/?/,
        getMessage: getRepoInformation
    }
];

module.exports.url = function(url, reply) {
    var matchInfo, githubObj;
    var matched = [];
    for (var i = 0; i < githubURLRegexes.length; i++) {
        var obj = githubURLRegexes[i];
        if ((matchInfo = obj.regex.exec(url))) {
            githubObj = obj;
            matched.push({
                githubObj: githubObj,
                matchInfo: matchInfo
            });
        }
    }
    if (matched.length) {
        /* Find the longest URL that was matched, that way subdirs get matched
         * to the most applicable parent dir.
         */
        var sorted = _.sortBy(matched, function(match) {
            return -match.matchInfo[0].length;
        });
        matchInfo = sorted[0].matchInfo;
        githubObj = sorted[0].githubObj;

        matchInfo.shift();
        matchInfo.push(reply);
        githubObj.getMessage.apply(githubObj, matchInfo);
    }
}
<commit_msg>Added github watch/unwatch<commit_after>var async = require('async'),
    fs = require('fs'),
    GitHubAPI = require('github'),
    _ = require('underscore');

var github = new GitHubAPI({
    version: "3.0.0",
    protocol: "https",
    timeout: 5000
});

function WatchManager() {
    var storageNamespace = "github",
        storageFilename = "watchman.json";

    var repos = {},
        issues = {};

    function GithubRepo(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.repos.getCommits({
                user: this.user,
                repo: this.repo
            }, function(err, res) {
                if (err) {
                    callback(err, false);
                } else {
                    var mostRecent = res[0];

                    // Update internal info
                    if (mostRecent.sha != self.lastCommitSeen) {
                        hasChanged = true;
                        self.lastCommitSeen = mostRecent.sha;
                        // Get just the first line of the commit message
                        var cMessage = mostRecent.commit.message;
                        self.lastCommitMessage = cMessage.split('\n')[0];
                        self.lastCommiter = mostRecent.committer.login;
                        self.lastCommitUrl = mostRecent.commit.url;
                    }
                    callback(null, hasChanged);
                }
            });
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- New commits on " + self.getKey(),
                       "Most recent - " + self.lastCommiter + ': ' +
                           self.lastCommitMessage];
            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo].join('/');
        }
    }

    function GithubIssue(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.issues.getRepoIssue({
                user: this.user,
                repo: this.repo,
                number: this.issue,
                direction: "desc"
            }, function(err, res) {
                var firstRes = res;
                // Check for comment changes
                if (err) {
                    callback(err, false);
                } else {
                    if (self.lastCommentNumber == res.comments) {
                        doneCheckingComments(firstRes, []);
                    } else {
                        github.issues.getComments({
                            user: self.user,
                            repo: self.repo,
                            number: self.issue
                        }, function(err, res) {
                            var comments = [];
                            if (!err) {
                                comments = res;
                            }
                            doneCheckingComments(firstRes, comments);
                        });
                    }
                }
            });

            function doneCheckingComments(res, comments) {
                var currCommNumber = parseInt(self.lastCommentNumber);
                if (self.title != res.title) {
                    self.title = res.title;
                }
                if (comments.length || res.state != self.lastStatus) {
                    hasChanged = true;
                    self.lastStatus = res.state;
                    self.lastCommentNumber = '' + res.comments;

                    // Get all commenters in last comments
                    var numComments = res.comments - currCommNumber;
                    var recentComments = _.first(comments, numComments);
                    var recentUsers = _.map(recentComments, function(comm) {
                        return comm.user.login;
                    });
                    self.lastCommenters = _.reduce(recentUsers, function(m, u) {
                        if (m.indexOf(u) == -1) {
                            m.push(u);
                        }
                        return m;
                    }, []);
                }
                callback(null, hasChanged);
            }
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- Update for issue " + this.getKey() + ".",
                "Current status: " + self.lastStatus + '.'];

            if (this.lastCommenters.length) {
                var commenters = JSON.stringify(this.lastCommenters);
                msg.push("New comments by " + commenters);
            }

            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo, this.issue].join('/');
        }
    }

    /* Repos are stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     lastCommitSeen: sha
     * }
     *
     * Issues stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     issue: issueNumber,
     *     lastStatus: status,
     *     lastCommentNumber: comment
     *     lastCommenters: [commenters]
     * }
     */
    this.load = function(callback) {
        bot.fsGetData(storageNamespace, storageFilename, function(err, res) {
            if (err) {
                // There's nothing there yet!
                var initData = '{ "repos": [], "issues": [] }';
                repos = {};
                issues = {};
                bot.fsStoreData(storageNamespace, storageFilename, initData,
                        function() {
                    callback();
                });
            } else {
                var savData = JSON.parse(res);
                var repoList = _.map(savData.repos, function(repoData) {
                    return new GithubRepo(repoData);
                });
                var issueList = _.map(savData.issues, function(issueData) {
                    return new GithubIssue(issueData);
                });
                repos = {};
                issues = {};
                _.each(repoList, function(repo) {
                    var key = repo.getKey();
                    repos[key] = repo;
                });
                _.each(issueList, function(issue) {
                    var key = issue.getKey();
                    issues[key] = issue;
                });
                callback();
            }
        });
    }

    this.overwrite = function(callback) {
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var data = JSON.stringify({ repos: repoList, issues: issueList });
        bot.fsStoreData(storageNamespace, storageFilename, data,
                function(err, res) {
            if (callback) callback();
        });
    }

    this.checkForUpdates = function(callback) {
        var self = this;
        var numChecked = 0;
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var repoLen = repoList.length,
            issueLen = issueList.length;
        var anyChanged = false;
        _.each(repoList, function(repo) {
            console.log("Checking " + repo.getKey() + " for updates");
            repo.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching repo " + repo.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(repo.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        _.each(issueList, function(issue) {
            console.log("Checking " + issue.getKey() + " for updates");
            issue.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching issue " + issue.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(issue.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        function maybeDone() {
            if (numChecked == repoLen + issueLen) {
                if (anyChanged) {
                    self.overwrite(function() {
                        if (callback) callback();
                    });
                } else {
                    if (callback) callback();
                }
            }
        }
    }

    this.watchRepo = function(username, repository, callback) {
        var self = this;
        var key = [username, repository].join('/');
        if (repos.hasOwnProperty(key)) {
            callback("Repo", key, "is already being watched.");
        } else {
            var repoData = { user: username, repo: repository };
            var repo = new GithubRepo(repoData);
            repo.checkForUpdates(function() {
                repos[key] = repo;
                self.overwrite(function() {
                    callback("Watching", key + ".", "Last commit seen:",
                            repo.lastCommitSeen);
                });
            });
        }
    }

    this.watchIssue = function(username, repository, issueNum, callback) {
        var self = this;
        var key = [username, repository, issueNum].join('/');
        if (issues.hasOwnProperty(key)) {
            callback("Issue", key, "is already being watched.");
        } else {
            var issueData = {
                user: username,
                repo: repository,
                issue: issueNum,
                title: '',
                lastStatus: '',
                lastCommentNumber: '',
                lastCommenters: []
            };
            var issue = new GithubIssue(issueData);
            issue.checkForUpdates(function(err, changed) {
                if (err) {
                    callback("Github response is dicked. Could not add", key);
                } else {
                    issues[key] = issue;
                    self.overwrite(function() {
                        callback("Now watching issue", key, '|', issue.title,
                            "|", issue.lastStatus);
                    });
                }
            });
        }
    }

    this.unwatchRepo = function(username, repository, callback) {
        var key = [username, repository].join('/');
        delete repos[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }

    this.unwatchIssue = function(username, repository, issueNum, callback) {
        var key = [username, repository, issueNum].join('/');
        delete issues[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }
}

var bot,
    watchMan = new WatchManager(),
    updateInterval = 60000 * 15;  // 15 Minutes

module.exports.init = function(b) {
    bot = b;
    watchMan.load(function() {
        function check() {
            watchMan.checkForUpdates(function() {
                setTimeout(check, updateInterval);
            });
        }
        check();
    });
}

var USER_REGEX = /github\.com\/(\w+)\/?/,
    REPO_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/?/,
    COMMIT_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/commit\/(\w+)\/?/,
    ISSUE_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/issues\/(\d+)\/?/,
    IO_PAGE_REGEX = /\/\/(\w+)\.github\.io\/((?:\w|-)+)\/?/;

/* Generates IRC message from github username/repo by querying that repo and
 * gathering various stats such as language and number of forks
 */
function getRepoInformation(username, reponame, cb) {
    github.repos.get({
        user: username,
        repo: reponame
    }, function(err, res) {
        if (err) {
            cb("Github response is dicked");
        } else {
            var name = res.name,
                description = res.description,
                language = res.language,
                forks = "Forks: " + res.forks_count;
            if (!language)
                language = "";
            else
                language = "| " + language;
            if (description.length > 60)
                description = description.substr(0, 40);
            if (description.length > 0)
                description = '| ' + description;

            cb(name, description, language, '| ', forks);
        }
    });
}

/* To add support for a new github link type, construct a regex and add it to
 * the declarations above. Add an object to this list containing two keys:
 *
 * regex -- the regex to use to try and match links
 * getMessage -- A function taking an argument for each group matched in the
 *     regex, as well as a final callback function, which is the text that the
 *     bot will say in the irc channel.
 */
var githubURLRegexes = [
    {
        regex: USER_REGEX,
        getMessage: function(username, cb) {
            github.user.getFrom({
                user: username
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var followers = res.followers,
                        following = res.following,
                        publicRepose = res.public_repos,
                        company = res.company;
                        if (!company) company = "";
                        else company = "Works for " + company + " |";

                    cb(username + ":", company, "Followers:",
                        followers, "| Following:", following);
                }
            });
        }
    },
    {
        regex: REPO_REGEX,
        getMessage: getRepoInformation
    },
    {
        regex: COMMIT_REGEX,
        getMessage: function(username, reponame, commit, cb) {
            github.repos.getCommit({
                user: username,
                repo: reponame,
                sha: commit
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var committer = res.committer.login,
                        message = res.commit.message;
                    // Extract first line of commit message
                    message = /.*/.exec(message);
                    if (message) message = message[0];
                    else message = "";
                    if (message.length > 50) message = message.substr(0, 50);

                    cb("Commit to", reponame, "by", committer + ":", message);
                }
            });
        }
    },
    {
        regex: ISSUE_REGEX,
        getMessage: function(username, reponame, issue, cb) {
            github.issues.getRepoIssue({
                user: username,
                repo: reponame,
                number: issue
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var title = res.title,
                        state = res.state;
                    cb("Issue for", reponame + ":", title, "|", state);
                }
            });
        }
    },
    {
        regex: IO_PAGE_REGEX,
        getMessage: getRepoInformation
    }
];

/* If a URL is said, try and match it to a github url and post info. */
module.exports.url = function(url, reply) {
    var matchInfo, githubObj;
    var matched = [];
    for (var i = 0; i < githubURLRegexes.length; i++) {
        var obj = githubURLRegexes[i];
        if ((matchInfo = obj.regex.exec(url))) {
            githubObj = obj;
            matched.push({
                githubObj: githubObj,
                matchInfo: matchInfo
            });
        }
    }
    if (matched.length) {
        /* Find the longest URL that was matched, that way subdirs get matched
         * to the most applicable parent dir.
         */
        var sorted = _.sortBy(matched, function(match) {
            return -match.matchInfo[0].length;
        });
        matchInfo = sorted[0].matchInfo;
        githubObj = sorted[0].githubObj;

        matchInfo.shift();
        matchInfo.push(reply);
        githubObj.getMessage.apply(githubObj, matchInfo);
    }
}

module.exports.commands = {
    github: {
        // Polls a github repo or issue and posts updates
        watch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.watchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.watchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: watch [repo|issue] username repo [issuenum]");
            }
        },
        unwatch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.unwatchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.unwatchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: unwatch [repo|issue] username repo [issuenum]");
            }
        }
    }
}
<|endoftext|>


<commit_before>/*
 * jQuery Plus Slider 1.2.6
 * By Jamy Golden
 * http://css-plus.com
 *
 * Copyright 2011
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
(function($){
    $.plusSlider = function(el, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;
        // Add a reverse reference to the DOM object
        base.$el.data('plusSlider', base);

        base.init = function(){
            base.options = $.extend({}, $.plusSlider.defaults, options);
            base.$slides = base.$el.children();
            base.$totalSlides = base.$slides.length;

            // Injected HTML elements
            base.$el.wrap('
');
            base.$slides.addClass('child');
            base.$slides.eq(0).addClass('current');

            // Slider/Fader Settings
            if(base.options.sliderType == 'slider'){
                base.$el.parent().addClass('plusTypeSlider');
                base.$slideWidth = base.$el.find(':first').outerWidth(true);
                base.$sliderWidth = base.$slideWidth * base.$totalSlides;
                base.$stopPosition = base.$sliderWidth - base.$slideWidth;
                base.$el.width(base.$sliderWidth);
                base.$el.children().show();
            }else{
                base.$el.parent().addClass('plusTypeFader');
                base.$el.children(':first').show();
            }
            if(base.$totalSlides === 1){
                base.options.autoPlay = false;
                base.options.createArrows = false;
                base.options.createPagination = false;
            }

            // Overide default CSS width
             if(base.options.width){
                base.$el.parent().width(base.options.width);
             }
             // Overide default CSS height
             if(base.options.height){
                base.$el.parent().height(base.options.height);
             }
            // Begin settings.pagination
            if(base.options.createPagination){
                // #slider-controls
                if(base.options.paginationBefore){
                    base.$el.before('
');
                    base.$sliderControls = base.$el.prev('.plusSlider-controls');
                } else{
                       base.$el.after('
');
                       base.$sliderControls = base.$el.next('.plusSlider-controls');
                   }
                   base.$sliderControls.wrap('
');
                // Pagination
                for (var i = 0; i < base.$totalSlides; i++){
                    base.$sliderControls.append('' + (i + 1) + '');
                }
                if(base.options.paginationWidth){
                     base.$sliderControls.width(base.$sliderControls.find('a').outerWidth(true) * base.$totalSlides);
                 }
                base.$sliderControls.find('a').click(function(){
                    base.toSlide($(this).attr('rel'));
                    return false;
                });
                base.$sliderControls.find('a').eq(0).addClass('current');
            } // End settings.pagination

            // Begin Functions
            base.nextSlide = function (direction){
                if(direction !== false){
                    direction = true;
                }
                if(base.options.sliderType == 'slider'){
                    if(direction == true && !base.$el.is(':animated')){
                        //stop position -1 to fix IE8 inconsistancy
                        if(base.$el.position().left > (base.$stopPosition - 1) * -1){
                            if(base.options.createPagination){
                                base.$sliderControls.find('a.current').removeClass('current').next().addClass('current');
                            }
                            base.$el.animate({
                                left: "-=" + base.$slideWidth + "px"
                            }, base.options.speed, base.options.sliderEasing);
                            base.$el.children('.current').removeClass('current').next().addClass('current');
                        }else{
                            if(base.options.createPagination){
                                base.$sliderControls.find('a:last').removeClass('current').siblings('a:first').addClass('current');
                            }
                            base.$el.animate({
                                left: 0
                            }, base.options.speed, base.options.sliderEasing);
                            base.$el.children('.current').removeClass('current').siblings(':first').addClass('current');
                        }
                    }else if(direction == false && !base.$el.is(':animated')){
                        if(base.$el.position().left < 0 && !base.$slides.is(':animated')){
                            if(base.options.createPagination){
                                base.$sliderControls.find('a.current').removeClass('current').prev().addClass('current');
                            }
                            base.$el.animate({
                                left: "+=" + base.$slideWidth + "px"
                            }, base.options.speed, base.options.sliderEasing);
                            base.$el.children('.current').removeClass('current').prev().addClass('current');
                        }else{
                            if(base.options.createPagination){
                                base.$sliderControls.find('a:first').removeClass('current').siblings('a:last').addClass('current');
                            }
                            base.$el.animate({
                                left: "-=" + base.$stopPosition + "px"
                            }, base.options.speed, base.options.sliderEasing);
                            base.$el.children('.current').removeClass('current').siblings(':last').addClass('current');
                        }
                    }
                }else{
                    if(direction == true && !base.$slides.is(':animated')){
                        if(base.$el.children(':last').is('.current')){
                            if(base.options.createPagination){
                                base.$sliderControls.find('a:last').removeClass('current').siblings('a:first').addClass('current');
                            }
                            base.$el.children('.current').removeClass('current').css('zIndex', 60).siblings().css('zIndex', 50);
                            base.$el.children(':first').css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                                base.$slides.not('.current').hide();
                            });
                        }else{
                            if(base.options.createPagination){
                                base.$sliderControls.find('a.current').removeClass('current').next().addClass('current');
                            }
                            base.$el.children('.current').removeClass('current').css('zIndex', 60).siblings().css('zIndex', 50).end().next().css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                                base.$slides.not('.current').hide();
                            });
                        }
                    }else if(direction == false && !base.$slides.is(':animated')){
                        if(base.$el.children(':first').is('.current')){
                            if(base.options.createPagination){
                                base.$sliderControls.find('a:first').removeClass('current').siblings('a:last').addClass('current');
                            }
                            base.$el.children('.current').removeClass('current').css('zIndex', 60).siblings().css('zIndex', 50);
                            base.$el.children(':last').css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                                base.$slides.not('.current').hide();
                            });
                        }else if(!base.$slides.is(':animated')){
                            if(base.options.createPagination){
                                base.$sliderControls.find('a.current').removeClass('current').prev().addClass('current');
                            }
                            base.$el.children('.current').removeClass('current').siblings().css('zIndex', 50).end().css('zIndex', 60).prev().css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                                base.$slides.not('.current').hide();
                            });
                        }
                    }
                }
                // Clear Timer
                if(base.options.autoPlay){
                    base.clearTimer();
                    base.beginTimer();
                }
                // Callback
                if (base.options.onSlide && typeof(base.options.onSlide) == "function") {
                    base.options.onSlide(base.$slides.filter('.current').index());
                }
            }

            base.toSlide = function(index){
                // Don't animate while animated
                if(!base.$slides.is(':animated')){
                    if(base.options.createPagination){
                        base.$sliderControls.find('a[rel="' + index + '"]').addClass('current').siblings().removeClass('current');
                    }
                    if(base.options.sliderType == 'slider'){
                        base.$el.animate({
                            left: base.$slideWidth * index * -1 + "px"
                        }, base.options.speed, base.options.sliderEasing);
                        base.$el.children('.current').removeClass('current').parent().children().eq(index).addClass('current');
                    }else{
                        base.$slides.eq(index).siblings().css('zIndex', 50).removeClass('current');
                        base.$slides.eq(index).css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                            base.$slides.not('.current').hide();
                        });
                    }
                    // Clear Timer
                    if(base.options.autoPlay){
                        base.clearTimer();
                        base.beginTimer();
                    }
                    // Callback
                    if (base.options.onSlide && typeof(base.options.onSlide) == "function") {
                        base.options.onSlide(index);
                    }
                }
            }
            // End Functions

            // Auto Play Begins
            if(base.options.autoPlay){
                base.clearTimer = function(){
                    // Clear the timer only ifit is set
                    if(base.timer){
                        window.clearInterval(base.timer);
                    }
                }
                base.beginTimer = function(){
                    base.timer = window.setInterval(function(){
                        base.nextSlide();
                    }, base.options.displayTime);
                }
                base.beginTimer();
                // Pause on hover
                if(base.options.pauseOnHover){
                    base.$el.hover(function(){
                        base.clearTimer();
                    }, function(){
                        base.beginTimer();
                    });
                }
            } // Auto Play Ends

            // Create Arrows
            if(base.options.createArrows){
                base.$el.before('prevnext').siblings('.next').click(function(){
                    base.nextSlide();
                    return false;
                });
                base.$el.siblings('.prev').click(function(){
                    base.nextSlide(false);
                    return false;
                });
            } // End Arrow Creation

            // Keyboard navigation
            if(base.options.keyboardNavigation){
                base.$el.click(function(){
                    $('.activePlusSlider').removeClass('activePlusSlider');
                    $(this).addClass('activePlusSlider');
                });
                $(window).keyup(function(e){
                    if(base.$el.is('.activePlusSlider')){
                        if(e.keyCode == 39){
                            base.nextSlide();
                        }else if(e.keyCode == 37){
                            base.nextSlide(false);
                        }
                    }
                });
            } // End Keyboard navigation

            // Pagination Titles
            if(base.options.paginationTitle){
                for (var i = 0; i < base.$totalSlides; i++){
                    base.$sliderControls.find('a[rel="' + i + '"]').text(base.$slides.eq(i).attr('data-title'));
                }
            } // End Pagination Titles

        };
        // Run initializer
        base.init();
    };
    $.plusSlider.defaults ={
        createArrows: true, // Creates forward and backward navigation
        createPagination: true, // Creates Numbered pagination
        paginationBefore: false, // Place the pagination above the slider within the HTML
        paginationWidth: true, // Automatically gives the pagination a dynamic width
        paginationTitle: false, // Checks for attribute 'data-title' on each slide and names the pagination accordingly

        displayTime: 4000, // The amount of time the slide waits before automatically moving on to the next one. This requires 'autoPlay: true'
        speed: 500, // The amount of time it takes for a slide to fade into another slide

        autoPlay: true, // Creats a times, looped 'slide-show'
        keyboardNavigation: true, // The keyboard's directional left and right arrows function as next and previous buttons
        pauseOnHover: true, // Autoplay does not continue ifsomeone hovers over Plus Slider.

        sliderEasing: 'linear', // Anything other than 'linear' and 'swing' requires the easing plugin
        sliderType: 'slider', // Choose whether the carousel is a 'slider' or a 'fader'

        width: false, // Overide the default CSS width
        height: false, // Overide the default CSS width

        onSlide: null // Callback function
    };
    $.fn.plusSlider = function(options){
        return this.each(function(){
            (new $.plusSlider(this, options));
        });
    };
})(jQuery);
<commit_msg>toSlide() is now the primary function. nextSlide() has been removed.<commit_after>/*
 * jQuery Plus Slider 1.2.6
 * By Jamy Golden
 * http://css-plus.com
 *
 * Copyright 2011
 * Free to use under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
(function($){
    $.plusSlider = function(el, options){
        // To avoid scope issues, use 'base' instead of 'this'
        // to reference this class from internal events and functions.
        var base = this;
        // Access to jQuery and DOM versions of element
        base.$el = $(el);
        base.el = el;
        // Add a reverse reference to the DOM object
        base.$el.data('plusSlider', base);

        base.init = function(){
            base.options = $.extend({}, $.plusSlider.defaults, options);
            // Vasic variables & Injected HTML elements
            base.$slides = base.$el.children();
            base.$totalSlides = base.$slides.length;
            base.$el.wrap('
');
            base.$wrap = base.$el.parent();
            base.$slides.addClass('child');
            base.$slides.eq(0).addClass('current');

            // Slider/Fader Settings
            if(base.options.sliderType == 'slider'){
                base.$wrap.addClass('plusTypeSlider');
                base.$slideWidth = base.$el.find(':first').outerWidth(true);
                base.$sliderWidth = base.$slideWidth * base.$totalSlides;
                base.$stopPosition = base.$sliderWidth - base.$slideWidth;
                base.$el.width(base.$sliderWidth);
                base.$slides.show();
            }else{
                base.$wrap.addClass('plusTypeFader');
                base.$slides.eq(0).show();
            }
            if(base.$totalSlides === 1){
                base.options.autoPlay = false;
                base.options.createArrows = false;
                base.options.createPagination = false;
            }

            // Overide default CSS width
            if(base.options.width) base.$wrap.width(base.options.width);
            // Overide default CSS height
            if(base.options.height) base.$wrap.height(base.options.height);
            // Begin settings.pagination
            if(base.options.createPagination){
                // #slider-controls
                if(base.options.paginationBefore){
                    base.$el.before('
');
                    base.$sliderControls = base.$el.prev('.plusSlider-controls');
                } else{
                   base.$el.after('
');
                   base.$sliderControls = base.$el.next('.plusSlider-controls');
                }
                base.$sliderControls.wrap('
');
                // Pagination
                for (var i = 0; i < base.$totalSlides; i++){
                    base.$sliderControls.append('' + (i + 1) + '');
                }
                if(base.options.paginationWidth){
                     base.$sliderControls.width(base.$sliderControls.find('a').outerWidth(true) * base.$totalSlides);
                 }
                base.$sliderControls.find('a').click(function(){
                    base.toSlide($(this).attr('rel'));
                    return false;
                });
                base.$sliderControls.find('a').eq(0).addClass('current');
            } // End settings.pagination

            // Add plusSlider data
            base.$el.data("slides",{ current: base.$el.children('.current').index() })
            base.$wrap.before(base.$el.data("slides").current);

            // Begin Functions
            base.toSlide = function (slide){
                if(slide == 'next' || slide == null) slide = base.$el.data("slides").current + 1;
                if(slide == 'prev') slide = base.$el.data("slides").current - 1;
                if(slide >= base.$totalSlides) slide = 0;
                if(slide <= -1) slide = base.$totalSlides -1;

                if(base.options.sliderType == 'slider'){
                    if(!base.$el.is(':animated')){
                        if(base.options.createPagination){
                            base.$sliderControls.find('a[rel="' + slide + '"]').addClass('current').siblings().removeClass('current');
                        }
                        base.$el.animate({
                            left: base.$slideWidth * slide * -1 + "px"
                        }, base.options.speed, base.options.sliderEasing);
                        base.$el.children('.current').removeClass('current').parent().children().eq(slide).addClass('current');
                    }
                }else{ // Begin Fader
                    if(!base.$slides.is(':animated')){

                        if(base.options.createPagination){
                            base.$sliderControls.find('a[rel="' + slide + '"]').addClass('current').siblings().removeClass('current');
                        }
                        base.$slides.eq(slide).css('zIndex', 100).addClass('current').fadeIn(base.options.speed, function(){
                            base.$slides.not('.current').hide();
                        }).siblings().css('zIndex', 50).removeClass('current');
                    }
                }
                // Clear Timer
                if(base.options.autoPlay){
                    base.clearTimer();
                    base.beginTimer();
                }
                // Callback
                if (base.options.onSlide && typeof(base.options.onSlide) == "function") {
                    base.options.onSlide(base.$slides.filter('.current').index());
                }

                base.$el.data("slides",{ current: base.$el.children('.current').index() })
                base.$wrap.before(base.$el.data("slides").current);
            }

            // Auto Play Begins
            if(base.options.autoPlay){
                base.clearTimer = function(){
                    // Clear the timer only ifit is set
                    if(base.timer){
                        window.clearInterval(base.timer);
                    }
                }
                base.beginTimer = function(){
                    base.timer = window.setInterval(function(){
                        base.toSlide('next');
                    }, base.options.displayTime);
                }
                base.beginTimer();
                // Pause on hover
                if(base.options.pauseOnHover){
                    base.$el.hover(function(){
                        base.clearTimer();
                    }, function(){
                        base.beginTimer();
                    });
                }
            } // Auto Play Ends

            // Create Arrows
            if(base.options.createArrows){
                base.$el.before('prevnext').siblings('.next').click(function(){
                    base.toSlide('next');
                    return false;
                }).siblings('.prev').click(function(){
                    base.toSlide('prev');
                    return false;
                });
            } // End Arrow Creation

            // Keyboard navigation
            if(base.options.keyboardNavigation){
                base.$el.click(function(){
                    $('.activePlusSlider').removeClass('activePlusSlider');
                    $(this).addClass('activePlusSlider');
                });
                $(window).keyup(function(e){
                    if(base.$el.is('.activePlusSlider')){
                        if(e.keyCode == 39){
                            base.toSlide();
                        }else if(e.keyCode == 37){
                            base.toSlide('prev');
                        }
                    }
                });
            } // End Keyboard navigation

            // Pagination Titles-
            if(base.options.paginationTitle){
                for (var i = 0; i < base.$totalSlides; i++){
                    base.$sliderControls.find('a[rel="' + i + '"]').text(base.$slides.eq(i).attr('data-title'));
                }
            } // End Pagination Titles

            // Pagination Thumbnails - FIREFOX 5+ ONLY
            if(base.options.paginationThumbnails){

                for(i = 0; i < base.$slides.length; i++){
                    var $this = base.$slides.eq(i);
                    if(!$this.attr('id')){
                        $this.attr('id', 'plusSlider-slide-' + $this.index());
                    }
                }

                base.$sliderControls.after($("
", {'class': "plusSlider-thumbnail"}));
                var sliderThumbnail = base.$sliderControls.next('.plusSlider-thumbnail');

                sliderThumbnail.css({'height':base.$el.height(), 'width':base.$wrap.width()}).siblings('.plusSlider-controls').find('a').hover(function(){
                    sliderThumbnail.css('background-image', '-moz-element(#' + base.$slides.eq($(this).attr('rel')).attr('id') + ')').toggleClass('plusSlider-active');
                });

            } // End Pagination Thumbnails

        };
        // Run initializer
        base.init();
    };
    $.plusSlider.defaults ={
        createArrows: true, // Creates forward and backward navigation
        createPagination: true, // Creates Numbered pagination
        paginationBefore: false, // Place the pagination above the slider within the HTML
        paginationWidth: true, // Automatically gives the pagination a dynamic width
        paginationTitle: false, // Checks for attribute 'data-title' on each slide and names the pagination accordingly
        paginationThumbnails: false, // FIREFOX 5+ ONLY - Creates thumbnails of the slides once you hover over the pagination

        displayTime: 4000, // The amount of time the slide waits before automatically moving on to the next one. This requires 'autoPlay: true'
        speed: 500, // The amount of time it takes for a slide to fade into another slide

        autoPlay: true, // Creats a times, looped 'slide-show'
        keyboardNavigation: true, // The keyboard's directional left and right arrows function as next and previous buttons
        pauseOnHover: true, // Autoplay does not continue ifsomeone hovers over Plus Slider.

        sliderEasing: 'linear', // Anything other than 'linear' and 'swing' requires the easing plugin
        sliderType: 'slider', // Choose whether the carousel is a 'slider' or a 'fader'

        width: false, // Overide the default CSS width
        height: false, // Overide the default CSS width

        onSlide: null // Callback function
    };
    $.fn.plusSlider = function(options){
        return this.each(function(){
            (new $.plusSlider(this, options));
        });
    };
})(jQuery);<|endoftext|>


<commit_before>var async = require('async'),
    fs = require('fs'),
    GitHubAPI = require('github'),
    _ = require('underscore');

var github = new GitHubAPI({
    version: "3.0.0",
    protocol: "https",
    timeout: 5000
});

function WatchManager() {
    var storageNamespace = "github",
        storageFilename = "watchman.json";

    var repos = {},
        issues = {};

    function GithubRepo(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.repos.getCommits({
                user: this.user,
                repo: this.repo
            }, function(err, res) {
                if (err) {
                    callback(err, false);
                } else {
                    var mostRecent = res[0];

                    // Update internal info
                    if (mostRecent.sha != self.lastCommitSeen) {
                        hasChanged = true;
                        self.lastCommitSeen = mostRecent.sha;
                        // Get just the first line of the commit message
                        var cMessage = mostRecent.commit.message;
                        self.lastCommitMessage = cMessage.split('\n')[0];
                        self.lastCommiter = mostRecent.committer.login;
                        self.lastCommitUrl = mostRecent.commit.url;
                    }
                    callback(null, hasChanged);
                }
            });
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- New commits on " + self.getKey(),
                       "Most recent - " + self.lastCommiter + ': ' +
                           self.lastCommitMessage];
            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo].join('/');
        }
    }

    function GithubIssue(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.issues.getRepoIssue({
                user: this.user,
                repo: this.repo,
                number: this.issue,
                direction: "desc"
            }, function(err, res) {
                var firstRes = res;
                // Check for comment changes
                if (err) {
                    callback(err, false);
                } else {
                    if (self.lastCommentNumber == res.comments) {
                        doneCheckingComments(firstRes, []);
                    } else {
                        github.issues.getComments({
                            user: self.user,
                            repo: self.repo,
                            number: self.issue
                        }, function(err, res) {
                            var comments = [];
                            if (!err) {
                                comments = res;
                            }
                            doneCheckingComments(firstRes, comments);
                        });
                    }
                }
            });

            function doneCheckingComments(res, comments) {
                var currCommNumber = parseInt(self.lastCommentNumber);
                if (self.title != res.title) {
                    self.title = res.title;
                }
                if (comments.length || res.state != self.lastStatus) {
                    hasChanged = true;
                    self.lastStatus = res.state;
                    self.lastCommentNumber = '' + res.comments;

                    // Get all commenters in last comments
                    var numComments = res.comments - currCommNumber;
                    var recentComments = _.first(comments, numComments);
                    var recentUsers = _.map(recentComments, function(comm) {
                        return comm.user.login;
                    });
                    self.lastCommenters = _.reduce(recentUsers, function(m, u) {
                        if (m.indexOf(u) == -1) {
                            m.push(u);
                        }
                        return m;
                    }, []);
                }
                callback(null, hasChanged);
            }
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- Update for issue " + this.getKey() + ".",
                "Current status: " + self.lastStatus + '.'];

            if (this.lastCommenters.length) {
                var commenters = JSON.stringify(this.lastCommenters);
                msg.push("New comments by " + commenters);
            }

            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo, this.issue].join('/');
        }
    }

    /* Repos are stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     lastCommitSeen: sha
     * }
     *
     * Issues stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     issue: issueNumber,
     *     lastStatus: status,
     *     lastCommentNumber: comment
     *     lastCommenters: [commenters]
     * }
     */
    this.load = function(callback) {
        bot.fsGetData(storageNamespace, storageFilename, function(err, res) {
            if (err) {
                // There's nothing there yet!
                var initData = '{ "repos": [], "issues": [] }';
                repos = {};
                issues = {};
                bot.fsStoreData(storageNamespace, storageFilename, initData,
                        function() {
                    callback();
                });
            } else {
                var savData = JSON.parse(res);
                var repoList = _.map(savData.repos, function(repoData) {
                    return new GithubRepo(repoData);
                });
                var issueList = _.map(savData.issues, function(issueData) {
                    return new GithubIssue(issueData);
                });
                repos = {};
                issues = {};
                _.each(repoList, function(repo) {
                    var key = repo.getKey();
                    repos[key] = repo;
                });
                _.each(issueList, function(issue) {
                    var key = issue.getKey();
                    issues[key] = issue;
                });
                callback();
            }
        });
    }

    this.overwrite = function(callback) {
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var data = JSON.stringify({ repos: repoList, issues: issueList });
        bot.fsStoreData(storageNamespace, storageFilename, data,
                function(err, res) {
            if (callback) callback();
        });
    }

    this.checkForUpdates = function(callback) {
        var self = this;
        var numChecked = 0;
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var repoLen = repoList.length,
            issueLen = issueList.length;
        var anyChanged = false;
        _.each(repoList, function(repo) {
            console.log("Checking " + repo.getKey() + " for updates");
            repo.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching repo " + repo.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(repo.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        _.each(issueList, function(issue) {
            console.log("Checking " + issue.getKey() + " for updates");
            issue.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching issue " + issue.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(issue.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        function maybeDone() {
            if (numChecked == repoLen + issueLen) {
                if (anyChanged) {
                    self.overwrite(function() {
                        if (callback) callback();
                    });
                } else {
                    if (callback) callback();
                }
            }
        }
    }

    this.watchRepo = function(username, repository, callback) {
        var self = this;
        var key = [username, repository].join('/');
        if (repos.hasOwnProperty(key)) {
            callback("Repo", key, "is already being watched.");
        } else {
            var repoData = { user: username, repo: repository };
            var repo = new GithubRepo(repoData);
            repo.checkForUpdates(function() {
                repos[key] = repo;
                self.overwrite(function() {
                    callback("Watching", key + ".", "Last commit seen:",
                            repo.lastCommitSeen);
                });
            });
        }
    }

    this.watchIssue = function(username, repository, issueNum, callback) {
        var self = this;
        var key = [username, repository, issueNum].join('/');
        if (issues.hasOwnProperty(key)) {
            callback("Issue", key, "is already being watched.");
        } else {
            var issueData = {
                user: username,
                repo: repository,
                issue: issueNum,
                title: '',
                lastStatus: '',
                lastCommentNumber: '',
                lastCommenters: []
            };
            var issue = new GithubIssue(issueData);
            issue.checkForUpdates(function(err, changed) {
                if (err) {
                    callback("Github response is dicked. Could not add", key);
                } else {
                    issues[key] = issue;
                    self.overwrite(function() {
                        callback("Now watching issue", key, '|', issue.title,
                            "|", issue.lastStatus);
                    });
                }
            });
        }
    }

    this.unwatchRepo = function(username, repository, callback) {
        var key = [username, repository].join('/');
        delete repos[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }

    this.unwatchIssue = function(username, repository, issueNum, callback) {
        var key = [username, repository, issueNum].join('/');
        delete issues[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }
}

var bot,
    watchMan = new WatchManager(),
    updateInterval = 60000 * 15;  // 15 Minutes

module.exports.init = function(b) {
    bot = b;
    watchMan.load(function() {
        function check() {
            watchMan.checkForUpdates(function() {
                setTimeout(check, updateInterval);
            });
        }
        check();
    });
}

var USER_REGEX = /github\.com\/(\w+)\/?/,
    REPO_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/?/,
    COMMIT_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/commit\/(\w+)\/?/,
    ISSUE_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/issues\/(\d+)\/?/,
    IO_PAGE_REGEX = /\/\/(\w+)\.github\.io\/((?:\w|-)+)\/?/;

/* Generates IRC message from github username/repo by querying that repo and
 * gathering various stats such as language and number of forks
 */
function getRepoInformation(username, reponame, cb) {
    github.repos.get({
        user: username,
        repo: reponame
    }, function(err, res) {
        if (err) {
            cb("Github response is dicked");
        } else {
            var name = res.name,
                description = res.description,
                language = res.language,
                forks = "Forks: " + res.forks_count;
            if (!language)
                language = "";
            else
                language = "| " + language;
            if (description.length > 60)
                description = description.substr(0, 40);
            if (description.length > 0)
                description = '| ' + description;

            cb(name, description, language, '| ', forks);
        }
    });
}

/* To add support for a new github link type, construct a regex and add it to
 * the declarations above. Add an object to this list containing two keys:
 *
 * regex -- the regex to use to try and match links
 * getMessage -- A function taking an argument for each group matched in the
 *     regex, as well as a final callback function, which is the text that the
 *     bot will say in the irc channel.
 */
var githubURLRegexes = [
    {
        regex: USER_REGEX,
        getMessage: function(username, cb) {
            github.user.getFrom({
                user: username
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var followers = res.followers,
                        following = res.following,
                        publicRepose = res.public_repos,
                        company = res.company;
                        if (!company) company = "";
                        else company = "Works for " + company + " |";

                    cb(username + ":", company, "Followers:",
                        followers, "| Following:", following);
                }
            });
        }
    },
    {
        regex: REPO_REGEX,
        getMessage: getRepoInformation
    },
    {
        regex: COMMIT_REGEX,
        getMessage: function(username, reponame, commit, cb) {
            github.repos.getCommit({
                user: username,
                repo: reponame,
                sha: commit
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var committer = res.committer.login,
                        message = res.commit.message;
                    // Extract first line of commit message
                    message = /.*/.exec(message);
                    if (message) message = message[0];
                    else message = "";
                    if (message.length > 50) message = message.substr(0, 50);

                    cb("Commit to", reponame, "by", committer + ":", message);
                }
            });
        }
    },
    {
        regex: ISSUE_REGEX,
        getMessage: function(username, reponame, issue, cb) {
            github.issues.getRepoIssue({
                user: username,
                repo: reponame,
                number: issue
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var title = res.title,
                        state = res.state;
                    cb("Issue for", reponame + ":", title, "|", state);
                }
            });
        }
    },
    {
        regex: IO_PAGE_REGEX,
        getMessage: getRepoInformation
    }
];

/* If a URL is said, try and match it to a github url and post info. */
module.exports.url = function(url, reply) {
    var matchInfo, githubObj;
    var matched = [];
    for (var i = 0; i < githubURLRegexes.length; i++) {
        var obj = githubURLRegexes[i];
        if ((matchInfo = obj.regex.exec(url))) {
            githubObj = obj;
            matched.push({
                githubObj: githubObj,
                matchInfo: matchInfo
            });
        }
    }
    if (matched.length) {
        /* Find the longest URL that was matched, that way subdirs get matched
         * to the most applicable parent dir.
         */
        var sorted = _.sortBy(matched, function(match) {
            return -match.matchInfo[0].length;
        });
        matchInfo = sorted[0].matchInfo;
        githubObj = sorted[0].githubObj;

        matchInfo.shift();
        matchInfo.push(reply);
        githubObj.getMessage.apply(githubObj, matchInfo);
    }
}

module.exports.commands = {
    github: {
        // Polls a github repo or issue and posts updates
        watch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.watchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.watchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: watch [repo|issue] username repo [issuenum]");
            }
        },
        unwatch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.unwatchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.unwatchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: unwatch [repo|issue] username repo [issuenum]");
            }
        }
    }
}
<commit_msg>Added a versioning system to github module config<commit_after>var async = require('async'),
    fs = require('fs'),
    GitHubAPI = require('github'),
    _ = require('underscore');

var github = new GitHubAPI({
    version: "3.0.0",
    protocol: "https",
    timeout: 5000
});

function WatchManager() {
    var storageNamespace = "github",
        storageFilename = "watchman.json";

    var repos = {},
        issues = {};

    function GithubRepo(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.repos.getCommits({
                user: this.user,
                repo: this.repo
            }, function(err, res) {
                if (err) {
                    callback(err, false);
                } else {
                    var mostRecent = res[0];

                    // Update internal info
                    if (mostRecent.sha != self.lastCommitSeen) {
                        hasChanged = true;
                        self.lastCommitSeen = mostRecent.sha;
                        // Get just the first line of the commit message
                        var cMessage = mostRecent.commit.message;
                        self.lastCommitMessage = cMessage.split('\n')[0];
                        self.lastCommiter = mostRecent.committer.login;
                        self.lastCommitUrl = mostRecent.commit.url;
                    }
                    callback(null, hasChanged);
                }
            });
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- New commits on " + self.getKey(),
                       "Most recent - " + self.lastCommiter + ': ' +
                           self.lastCommitMessage];
            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo].join('/');
        }
    }

    function GithubIssue(dataObj) {
        for (var prop in dataObj) this[prop] = dataObj[prop];

        this.checkForUpdates = function(callback) {
            var self = this;
            var hasChanged = false;
            github.issues.getRepoIssue({
                user: this.user,
                repo: this.repo,
                number: this.issue,
                direction: "desc"
            }, function(err, res) {
                var firstRes = res;
                // Check for comment changes
                if (err) {
                    callback(err, false);
                } else {
                    if (self.lastCommentNumber == res.comments) {
                        doneCheckingComments(firstRes, []);
                    } else {
                        github.issues.getComments({
                            user: self.user,
                            repo: self.repo,
                            number: self.issue
                        }, function(err, res) {
                            var comments = [];
                            if (!err) {
                                comments = res;
                            }
                            doneCheckingComments(firstRes, comments);
                        });
                    }
                }
            });

            function doneCheckingComments(res, comments) {
                var currCommNumber = parseInt(self.lastCommentNumber);
                if (self.title != res.title) {
                    self.title = res.title;
                }
                if (comments.length || res.state != self.lastStatus) {
                    hasChanged = true;
                    self.lastStatus = res.state;
                    self.lastCommentNumber = '' + res.comments;

                    // Get all commenters in last comments
                    var numComments = res.comments - currCommNumber;
                    var recentComments = _.first(comments, numComments);
                    var recentUsers = _.map(recentComments, function(comm) {
                        return comm.user.login;
                    });
                    self.lastCommenters = _.reduce(recentUsers, function(m, u) {
                        if (m.indexOf(u) == -1) {
                            m.push(u);
                        }
                        return m;
                    }, []);
                }
                callback(null, hasChanged);
            }
        }

        this.generateUpdateMessage = function() {
            var self = this;
            var msg = ["Github -- Update for issue " + this.getKey() + ".",
                "Current status: " + self.lastStatus + '.'];

            if (this.lastCommenters.length) {
                var commenters = JSON.stringify(this.lastCommenters);
                msg.push("New comments by " + commenters);
            }

            return msg;
        }

        this.getKey = function() {
            return [this.user, this.repo, this.issue].join('/');
        }
    }

    /* Repos are stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     lastCommitSeen: sha
     * }
     *
     * Issues stored as:
     * {
     *     user: username,
     *     repo: repository,
     *     issue: issueNumber,
     *     lastStatus: status,
     *     lastCommentNumber: comment
     *     lastCommenters: [commenters]
     * }
     */
    this.load = function(callback) {
        var self = this;
        bot.fsGetData(storageNamespace, storageFilename, function(err, res) {
            if (err) {
                // There's nothing there yet!
                var initData = JSON.stringify({
                    repos: [],
                    issues: [],
                    version: "1.0"
                });
                repos = {};
                issues = {};
                bot.fsStoreData(storageNamespace, storageFilename, initData,
                        function() {
                    callback();
                });
            } else {
                var savData = JSON.parse(res);
                if (res.hasOwnProperty('version')) {
                    self.configVersion = res.version;
                } else {
                    self.configVersion = '1.0';
                }
                var repoList = _.map(savData.repos, function(repoData) {
                    return new GithubRepo(repoData);
                });
                var issueList = _.map(savData.issues, function(issueData) {
                    return new GithubIssue(issueData);
                });
                repos = {};
                issues = {};
                _.each(repoList, function(repo) {
                    var key = repo.getKey();
                    repos[key] = repo;
                });
                _.each(issueList, function(issue) {
                    var key = issue.getKey();
                    issues[key] = issue;
                });
                callback();
            }
        });
    }

    this.overwrite = function(callback) {
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var data = JSON.stringify({
            repos: repoList,
            issues: issueList,
            version: this.configVersion
        });
        bot.fsStoreData(storageNamespace, storageFilename, data,
                function(err, res) {
            if (callback) callback();
        });
    }

    this.checkForUpdates = function(callback) {
        var self = this;
        var numChecked = 0;
        var repoList = _.values(repos),
            issueList = _.values(issues);
        var repoLen = repoList.length,
            issueLen = issueList.length;
        var anyChanged = false;
        _.each(repoList, function(repo) {
            console.log("Checking " + repo.getKey() + " for updates");
            repo.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching repo " + repo.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(repo.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        _.each(issueList, function(issue) {
            console.log("Checking " + issue.getKey() + " for updates");
            issue.checkForUpdates(function(err, changed) {
                numChecked++;
                if (err) {
                    bot.say("Error reaching issue " + issue.getKey());
                } else if (changed) {
                    anyChanged = true;
                    bot.say(issue.generateUpdateMessage().join(' '));
                }
                maybeDone();
            });
        });
        function maybeDone() {
            if (numChecked == repoLen + issueLen) {
                if (anyChanged) {
                    self.overwrite(function() {
                        if (callback) callback();
                    });
                } else {
                    if (callback) callback();
                }
            }
        }
    }

    this.watchRepo = function(username, repository, callback) {
        var self = this;
        var key = [username, repository].join('/');
        if (repos.hasOwnProperty(key)) {
            callback("Repo", key, "is already being watched.");
        } else {
            var repoData = { user: username, repo: repository };
            var repo = new GithubRepo(repoData);
            repo.checkForUpdates(function() {
                repos[key] = repo;
                self.overwrite(function() {
                    callback("Watching", key + ".", "Last commit seen:",
                            repo.lastCommitSeen);
                });
            });
        }
    }

    this.watchIssue = function(username, repository, issueNum, callback) {
        var self = this;
        var key = [username, repository, issueNum].join('/');
        if (issues.hasOwnProperty(key)) {
            callback("Issue", key, "is already being watched.");
        } else {
            var issueData = {
                user: username,
                repo: repository,
                issue: issueNum,
                title: '',
                lastStatus: '',
                lastCommentNumber: '',
                lastCommenters: []
            };
            var issue = new GithubIssue(issueData);
            issue.checkForUpdates(function(err, changed) {
                if (err) {
                    callback("Github response is dicked. Could not add", key);
                } else {
                    issues[key] = issue;
                    self.overwrite(function() {
                        callback("Now watching issue", key, '|', issue.title,
                            "|", issue.lastStatus);
                    });
                }
            });
        }
    }

    this.unwatchRepo = function(username, repository, callback) {
        var key = [username, repository].join('/');
        delete repos[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }

    this.unwatchIssue = function(username, repository, issueNum, callback) {
        var key = [username, repository, issueNum].join('/');
        delete issues[key];
        this.overwrite(function() {
            callback("Stopped watching", key);
        });
    }
}

var bot,
    watchMan = new WatchManager(),
    updateInterval = 60000 * 15;  // 15 Minutes

module.exports.init = function(b) {
    bot = b;
    watchMan.load(function() {
        function check() {
            watchMan.checkForUpdates(function() {
                setTimeout(check, updateInterval);
            });
        }
        check();
    });
}

var USER_REGEX = /github\.com\/(\w+)\/?/,
    REPO_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/?/,
    COMMIT_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/commit\/(\w+)\/?/,
    ISSUE_REGEX = /github\.com\/(\w+)\/((?:\w|-)+)\/issues\/(\d+)\/?/,
    IO_PAGE_REGEX = /\/\/(\w+)\.github\.io\/((?:\w|-)+)\/?/;

/* Generates IRC message from github username/repo by querying that repo and
 * gathering various stats such as language and number of forks
 */
function getRepoInformation(username, reponame, cb) {
    github.repos.get({
        user: username,
        repo: reponame
    }, function(err, res) {
        if (err) {
            cb("Github response is dicked");
        } else {
            var name = res.name,
                description = res.description,
                language = res.language,
                forks = "Forks: " + res.forks_count;
            if (!language)
                language = "";
            else
                language = "| " + language;
            if (description.length > 60)
                description = description.substr(0, 40);
            if (description.length > 0)
                description = '| ' + description;

            cb(name, description, language, '| ', forks);
        }
    });
}

/* To add support for a new github link type, construct a regex and add it to
 * the declarations above. Add an object to this list containing two keys:
 *
 * regex -- the regex to use to try and match links
 * getMessage -- A function taking an argument for each group matched in the
 *     regex, as well as a final callback function, which is the text that the
 *     bot will say in the irc channel.
 */
var githubURLRegexes = [
    {
        regex: USER_REGEX,
        getMessage: function(username, cb) {
            github.user.getFrom({
                user: username
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var followers = res.followers,
                        following = res.following,
                        publicRepose = res.public_repos,
                        company = res.company;
                        if (!company) company = "";
                        else company = "Works for " + company + " |";

                    cb(username + ":", company, "Followers:",
                        followers, "| Following:", following);
                }
            });
        }
    },
    {
        regex: REPO_REGEX,
        getMessage: getRepoInformation
    },
    {
        regex: COMMIT_REGEX,
        getMessage: function(username, reponame, commit, cb) {
            github.repos.getCommit({
                user: username,
                repo: reponame,
                sha: commit
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var committer = res.committer.login,
                        message = res.commit.message;
                    // Extract first line of commit message
                    message = /.*/.exec(message);
                    if (message) message = message[0];
                    else message = "";
                    if (message.length > 50) message = message.substr(0, 50);

                    cb("Commit to", reponame, "by", committer + ":", message);
                }
            });
        }
    },
    {
        regex: ISSUE_REGEX,
        getMessage: function(username, reponame, issue, cb) {
            github.issues.getRepoIssue({
                user: username,
                repo: reponame,
                number: issue
            }, function(err, res) {
                if (err) {
                    cb("Github response is dicked");
                } else {
                    var title = res.title,
                        state = res.state;
                    cb("Issue for", reponame + ":", title, "|", state);
                }
            });
        }
    },
    {
        regex: IO_PAGE_REGEX,
        getMessage: getRepoInformation
    }
];

/* If a URL is said, try and match it to a github url and post info. */
module.exports.url = function(url, reply) {
    var matchInfo, githubObj;
    var matched = [];
    for (var i = 0; i < githubURLRegexes.length; i++) {
        var obj = githubURLRegexes[i];
        if ((matchInfo = obj.regex.exec(url))) {
            githubObj = obj;
            matched.push({
                githubObj: githubObj,
                matchInfo: matchInfo
            });
        }
    }
    if (matched.length) {
        /* Find the longest URL that was matched, that way subdirs get matched
         * to the most applicable parent dir.
         */
        var sorted = _.sortBy(matched, function(match) {
            return -match.matchInfo[0].length;
        });
        matchInfo = sorted[0].matchInfo;
        githubObj = sorted[0].githubObj;

        matchInfo.shift();
        matchInfo.push(reply);
        githubObj.getMessage.apply(githubObj, matchInfo);
    }
}

module.exports.commands = {
    github: {
        // Polls a github repo or issue and posts updates
        watch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.watchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.watchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: watch [repo|issue] username repo [issuenum]");
            }
        },
        unwatch: function(r, p, reply) {
            var watchType = p[0];

            if (watchType == 'repo') {
                var user = p[1],
                    repo = p[2];
                watchMan.unwatchRepo(user, repo, reply);
            } else if (watchType == 'issue') {
                var user = p[1],
                    repo = p[2],
                    issueNum = p[3];
                watchMan.unwatchIssue(user, repo, issueNum, reply);
            } else {
                reply("Usage: unwatch [repo|issue] username repo [issuenum]");
            }
        }
    }
}
<|endoftext|>


<commit_before>Components.utils.import('chrome://greasemonkey-modules/content/util.js'); // ref'd in XUL

var gScriptId = decodeURIComponent(location.hash.substring(1));
var gScript = GM_util.getService().config.getMatchingScripts(function(script) {
  return script && (script.id == gScriptId);
})[0];

var gScriptExcludesEl;
var gScriptMatchesEl;
var gScriptIncludesEl;
var gTabboxEl;
var gUserExcludesEl;
var gUserMatchesEl;
var gUserIncludesEl;
var gUserTabEl;

window.addEventListener('load', function() {
  // I wanted "%s" but % is reserved in a DTD and I don't know the literal.
  document.title = document.title.replace('!!', gScript.localized.name);

  var gTabboxEl = document.getElementsByTagName('tabbox')[0];
  gUserTabEl = gTabboxEl.tabs.getItemAtIndex(0);

  gUserIncludesEl = document.getElementById('user-includes');
  gUserMatchesEl = document.getElementById('user-matches');
  gUserExcludesEl = document.getElementById('user-excludes');
  gScriptIncludesEl = document.getElementById('script-includes');
  gScriptMatchesEl = document.getElementById('script-matches');
  gScriptExcludesEl = document.getElementById('script-excludes');

  gScriptIncludesEl.pages = gScript.includes;
  gScriptIncludesEl.onAddUserExclude = function(url) {
    gUserExcludesEl.addPage(url);
    gTabboxEl.selectedTab = gUserTabEl;
  };
  gUserIncludesEl.pages = gScript.userIncludes;

  for (var i = 0; i < gScript.matches.length; i++) {
    gScriptMatchesEl.addPage(gScript.matches[i].pattern);
  }
  /*
  gScriptMatchesEl.onAddUserExclude = function(url) {
    gUserExcludeEl.addPage(url);
    gTabboxEl.selectedTab = gUserTabEl;
  };
  */
  for (var i = 0; i < gScript.userMatches.length; i++) {
    gUserMatchesEl.addPage(gScript.userMatches[i].pattern);
  }

  gScriptExcludesEl.pages = gScript.excludes;
  gScriptExcludesEl.onAddUserInclude = function(url) {
    gUserIncludesEl.addPage(url);
    gTabboxEl.selectedTab = gUserTabEl;
  };
  gUserExcludesEl.pages = gScript.userExcludes;
}, false);

function onDialogAccept() {
  // gScript.includes = gScriptIncludesEl.pages;
  gScript.userIncludes = gUserIncludesEl.pages;
  // gScript.matches = gScriptMatchesEl.pages;
  gScript.userMatches = gUserMatchesEl.pages;
  // gScript.excludes = gScriptExcludesEl.pages;
  gScript.userExcludes = gUserExcludesEl.pages;
  GM_util.getService().config._changed(gScript, "cludes");
}
<commit_msg>Remove commented-out code in scriptprefs.js.<commit_after>Components.utils.import('chrome://greasemonkey-modules/content/util.js'); // ref'd in XUL

var gScriptId = decodeURIComponent(location.hash.substring(1));
var gScript = GM_util.getService().config.getMatchingScripts(function(script) {
  return script && (script.id == gScriptId);
})[0];

var gScriptExcludesEl;
var gScriptMatchesEl;
var gScriptIncludesEl;
var gTabboxEl;
var gUserExcludesEl;
var gUserMatchesEl;
var gUserIncludesEl;
var gUserTabEl;

window.addEventListener('load', function() {
  // I wanted "%s" but % is reserved in a DTD and I don't know the literal.
  document.title = document.title.replace('!!', gScript.localized.name);

  var gTabboxEl = document.getElementsByTagName('tabbox')[0];
  gUserTabEl = gTabboxEl.tabs.getItemAtIndex(0);

  gUserIncludesEl = document.getElementById('user-includes');
  gUserMatchesEl = document.getElementById('user-matches');
  gUserExcludesEl = document.getElementById('user-excludes');
  gScriptIncludesEl = document.getElementById('script-includes');
  gScriptMatchesEl = document.getElementById('script-matches');
  gScriptExcludesEl = document.getElementById('script-excludes');

  gScriptIncludesEl.pages = gScript.includes;
  gScriptIncludesEl.onAddUserExclude = function(url) {
    gUserExcludesEl.addPage(url);
    gTabboxEl.selectedTab = gUserTabEl;
  };
  gUserIncludesEl.pages = gScript.userIncludes;

  for (var i = 0; i < gScript.matches.length; i++) {
    gScriptMatchesEl.addPage(gScript.matches[i].pattern);
  }
  for (var i = 0; i < gScript.userMatches.length; i++) {
    gUserMatchesEl.addPage(gScript.userMatches[i].pattern);
  }

  gScriptExcludesEl.pages = gScript.excludes;
  gScriptExcludesEl.onAddUserInclude = function(url) {
    gUserIncludesEl.addPage(url);
    gTabboxEl.selectedTab = gUserTabEl;
  };
  gUserExcludesEl.pages = gScript.userExcludes;
}, false);

function onDialogAccept() {
  gScript.userIncludes = gUserIncludesEl.pages;
  gScript.userMatches = gUserMatchesEl.pages;
  gScript.userExcludes = gUserExcludesEl.pages;
  GM_util.getService().config._changed(gScript, "cludes");
}
<|endoftext|>


<commit_before>$(function() {
    var show_popup = $.db('show_popup') === "1";
    if(!show_popup) {
        chrome.tabs.getSelected(null, function(tab) {
            chrome.extension.getBackgroundPage().readLater(tab);
        });
        window.close();
    } else {
        $('ul.links li > a.add').click(function() {
            chrome.tabs.getSelected(null, function(tab) {
                chrome.extension.getBackgroundPage().readLater(tab);
            });
        });

        $('ul.links li > a.text').click(function() {
            chrome.tabs.getSelected(null, function(tab) {
                chrome.tabs.update(tab.id, {
                    url: "http://www.instapaper.com/text?u=" + encodeURIComponent(tab.url)
                });
            });
        });

        $('ul.links li > a.unread').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/u"
            });
        });

        $('ul.links li > a.starred').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/starred"
            });
        });

        $('ul.links li > a.archive').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/archive"
            });
        });

        $('ul.links li > a.options').click(function() {
            chrome.tabs.create({url: chrome.extension.getURL('options.html')});
        });

        $('ul.links li > a').click(function () {
            window.close();
            return false;
        });
    }
});
<commit_msg>closing window inside the callback for get selected tab<commit_after>$(function() {
    var show_popup = $.db('show_popup') === "1";
    if(!show_popup) {
        chrome.tabs.getSelected(null, function(tab) {
            chrome.extension.getBackgroundPage().readLater(tab);
            window.close();
        });
    } else {
        $('ul.links li > a.add').click(function() {
            chrome.tabs.getSelected(null, function(tab) {
                chrome.extension.getBackgroundPage().readLater(tab);
                window.close();
            });
        });

        $('ul.links li > a.text').click(function() {
            chrome.tabs.getSelected(null, function(tab) {
                chrome.tabs.update(tab.id, {
                    url: "http://www.instapaper.com/text?u=" + encodeURIComponent(tab.url)
                });
                window.close();
            });
        });

        $('ul.links li > a.unread').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/u"
            });
            window.close();
        });

        $('ul.links li > a.starred').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/starred"
            });
            window.close();
        });

        $('ul.links li > a.archive').click(function() {
            chrome.tabs.create({
                url: "http://www.instapaper.com/archive"
            });
            window.close();
        });

        $('ul.links li > a.options').click(function() {
            chrome.tabs.create({url: chrome.extension.getURL('options.html')});
            window.close();
        });

        $('ul.links li > a').click(function () {
            return false;
        });
    }
});
<|endoftext|>


<commit_before>var tagname = "tcvideo"
var data1 = '

'
$(document).ready(function() {
    var objs = $(tagname);
	if (objs.size() <= 0)
		return;
	for (var i in objs) {
		var tc = objs.get(i);
		$(tc).append(data1 + $(tc).attr("src") + data2);
	}

    var initVideoSrc = function(obj, jp) {
	$(obj).append("如果无法观看视频, 请点击在线观看" +
	"(或点击下载)");
    };

});
<commit_msg>upper failed, test again<commit_after>var tagname = "tcvideo"
var data1 = '

'
$(document).ready(function() {
    var objs = $(tagname);
	if (objs.size() <= 0)
		return;
	for (var i in objs) {
		var tc = objs.get(i);
		var src = $(tc).attr("src") + "&auto=0"
		$(tc).append(data1 + src + data2);
	}

    var initVideoSrc = function(obj, jp) {
	$(obj).append("如果无法观看视频, 请点击在线观看" +
	"(或点击下载)");
    };

});
<|endoftext|>


<commit_before>var _seperator = '_';

var _handlerPartnerMenu = function (event) {
  event.preventDefault();
  appendToHashTag(event.data);
};

function createLinkItem (item) {
  var _a = $("<a/>", { href: "#" + item.link });
  $("<i/>", { class: item.icon }).appendTo(_a);
  $("<span/>", { text: " " + item.name }).appendTo(_a);
  return _a;
}

function createSingleLevelMenuItem (item) {
  return $("<li/>").append(createLinkItem(item));
}

function createMultiLevelMenuItem (item, _part_handler) {
  item.link = "";
  var _a = createLinkItem(item);
  if (_part_handler) {
    $("<span/>", { class: "label label-success pull-right", text: item.sub.length }).appendTo(_a);
  }
  else {
    $("<span/>", { class: "label label-primary pull-right", text: item.sub.length - 1 }).appendTo(_a);
  }

  var _ul = $("<ul/>", { class: "treeview-menu" });
  $.each(item.sub, function (index, subitem) {
    if (_part_handler) {
      subitem.icon = "fa fa-user";
      _ul.append(createSingleLevelMenuItem(subitem).click(subitem.link, _part_handler));
    }
    else {
      subitem.icon = index == 0 ? "fa fa-certificate" : "fa fa-circle-o";
      _ul.append(createSingleLevelMenuItem(subitem));
    }
  });

  return $("<li/>", { class: "treeview" }).append(_a).append(_ul);
}

function renderEnvironmentMenuItems () {
  var menu_env = $("#menu-env");
  $.each(menu_env_data, function (index, item) {
    menu_env.append(item.sub
      ? createMultiLevelMenuItem(item)
      : createSingleLevelMenuItem(item));
  });
}

function renderPartnerMenuItems () {
  var menu_part = $("#menu-part");
  $.each(menu_part_data, function (index, item) {
    menu_part.append(createMultiLevelMenuItem(item, _handlerPartnerMenu));
  });
}

function hasHasTagInUrl () {
  return window.location.hash.length > 0;
}

function extractHashTags () {
  var tags = window.location.hash.substr(1).split(_seperator);
  return {
    "env": tags[0],
    "part": tags[1],
  };
}

function appendToHashTag (suffix) {
  var tag = extractHashTags();
  var result = false;
  if (tag.env) {
    window.location.hash = tag.part == suffix ? tag.env : tag.env + _seperator + suffix;
    result = true;
  }
  return result;
}

function activateTaggedMenuPath () {
  activateTaggedMenuPathForSingleMenu("#menu-env", "env");
  activateTaggedMenuPathForSingleMenu("#menu-part", "part");
}

function activateTaggedMenuPathForSingleMenu (_menu_prefix, _tag_name) {
  $(_menu_prefix + " li[class~=active]").removeClass("active");
  var tags = extractHashTags();
  if (tags.env || tags.part) {
    $.each(tags, function (index, tag) {
      if (tag) {
        var selector = _menu_prefix + " a[href=#" + tag + "]";
        var target = $(selector);
        if (target) {
          target.parent("li").addClass("active");
          target.parent("li").parent().parent("li").addClass("active");
        }
      }
    });
  }
  // Only when it's expanded
  if (!$(_menu_prefix + " .sidebar-collapse").length) {
    if (tags[_tag_name]) {
      // Collapse other expanded menu items
      var selector = "a[href=#" + tags[_tag_name] + "]";
      $(_menu_prefix + " ul.menu-open").each(function (index) {
        if ($(this).find(selector).length == 0) {
          $(this).siblings().trigger("click");
        };
      });
    }
    else {
      // For default page, just collapse every item
      $(_menu_prefix + " ul.menu-open").siblings().trigger("click");
    }
  }
}
<commit_msg>Adjust color of labels on partner menu<commit_after>var _seperator = '_';

var _handlerPartnerMenu = function (event) {
  event.preventDefault();
  appendToHashTag(event.data);
};

function createLinkItem (item) {
  var _a = $("<a/>", { href: "#" + item.link });
  $("<i/>", { class: item.icon }).appendTo(_a);
  $("<span/>", { text: " " + item.name }).appendTo(_a);
  return _a;
}

function createSingleLevelMenuItem (item) {
  return $("<li/>").append(createLinkItem(item));
}

function createMultiLevelMenuItem (item, _part_handler) {
  item.link = "";
  var _a = createLinkItem(item);
  if (_part_handler) {
    $("<span/>", { class: "label pull-right", style: "background-color: #A19F9F;", text: item.sub.length }).appendTo(_a);
  }
  else {
    $("<span/>", { class: "label label-primary pull-right", text: item.sub.length - 1 }).appendTo(_a);
  }

  var _ul = $("<ul/>", { class: "treeview-menu" });
  $.each(item.sub, function (index, subitem) {
    if (_part_handler) {
      subitem.icon = "fa fa-user";
      _ul.append(createSingleLevelMenuItem(subitem).click(subitem.link, _part_handler));
    }
    else {
      subitem.icon = index == 0 ? "fa fa-certificate" : "fa fa-circle-o";
      _ul.append(createSingleLevelMenuItem(subitem));
    }
  });

  return $("<li/>", { class: "treeview" }).append(_a).append(_ul);
}

function renderEnvironmentMenuItems () {
  var menu_env = $("#menu-env");
  $.each(menu_env_data, function (index, item) {
    menu_env.append(item.sub
      ? createMultiLevelMenuItem(item)
      : createSingleLevelMenuItem(item));
  });
}

function renderPartnerMenuItems () {
  var menu_part = $("#menu-part");
  $.each(menu_part_data, function (index, item) {
    menu_part.append(createMultiLevelMenuItem(item, _handlerPartnerMenu));
  });
}

function hasHasTagInUrl () {
  return window.location.hash.length > 0;
}

function extractHashTags () {
  var tags = window.location.hash.substr(1).split(_seperator);
  return {
    "env": tags[0],
    "part": tags[1],
  };
}

function appendToHashTag (suffix) {
  var tag = extractHashTags();
  var result = false;
  if (tag.env) {
    window.location.hash = tag.part == suffix ? tag.env : tag.env + _seperator + suffix;
    result = true;
  }
  return result;
}

function activateTaggedMenuPath () {
  activateTaggedMenuPathForSingleMenu("#menu-env", "env");
  activateTaggedMenuPathForSingleMenu("#menu-part", "part");
}

function activateTaggedMenuPathForSingleMenu (_menu_prefix, _tag_name) {
  $(_menu_prefix + " li[class~=active]").removeClass("active");
  var tags = extractHashTags();
  if (tags.env || tags.part) {
    $.each(tags, function (index, tag) {
      if (tag) {
        var selector = _menu_prefix + " a[href=#" + tag + "]";
        var target = $(selector);
        if (target) {
          target.parent("li").addClass("active");
          target.parent("li").parent().parent("li").addClass("active");
        }
      }
    });
  }
  // Only when it's expanded
  if (!$(_menu_prefix + " .sidebar-collapse").length) {
    if (tags[_tag_name]) {
      // Collapse other expanded menu items
      var selector = "a[href=#" + tags[_tag_name] + "]";
      $(_menu_prefix + " ul.menu-open").each(function (index) {
        if ($(this).find(selector).length == 0) {
          $(this).siblings().trigger("click");
        };
      });
    }
    else {
      // For default page, just collapse every item
      $(_menu_prefix + " ul.menu-open").siblings().trigger("click");
    }
  }
}
<|endoftext|>