<commit_before>/* global pillstreak */
window.pillstreak = (function() {
    var KEYS = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down',
    };

    var CONF = {
        ANIM_SPEED: 100,
        SHIFT_SPEED: 110,
        TICK: 100,
        INFECTION_RATE: 0.4,
        DEBUG_SHIFT: false,
    }

    var INSTRUCTIONS = [
        "You are not well.",
        "But, you are not powerless!",
        "Combine pills to form Good Habits.",
        "Avoid letting the infection spread.",
        "The stronger the infection...",
        "the better you'll have to be with your pills.",
        "Swipe or use arrow keys to move.",
        "Swipe or use arrow keys to move.",
        "Swipe or use arrow keys to move.",
    ];

    var exports = {
        init: function() {
            this.$game = document.querySelector('#game');
            this.$$cells = document.querySelectorAll(".cell");
            this.$points = document.querySelector('#points');
            this.$high = document.querySelector('#high');
            this.$health = document.querySelector('#health_points');
            this.$info = document.querySelector('#info');
            this.$infoText = document.querySelector('#info-text');
            this.$restart = document.querySelector('#restart');

            this.lost = false;
            this.$restart.classList.add('hidden');
            this.$points.innerHTML = '0';
            this.$health.innerHTML = '10';

            var i, row, col;
            for (i=0; i<this.$$cells.length; i++) {
                row = i % 4;
                col = parseInt(i / 4, 10);
                this.$$cells[i].setAttribute('type', 'free');
                this.$$cells[i].setAttribute('row', row);
                this.$$cells[i].setAttribute('col', col);
                this.$$cells[i].setAttribute('level', '');
            }

            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');

            this.$game.focus();
            document.body.onkeyup = function(ev) {
                pillstreak.shiftAllCells(KEYS[ev.keyCode])
            };

            Hammer(document.body, {
                swipe: true,
                swipe_velocity: 0.1,
            }).on('swipeup swipedown swipeleft swiperight', function(ev) {
                pillstreak.shiftAllCells(ev.gesture.direction);
            });

            document.body.ontouchstart = function(ev) {
                ev.preventDefault();
            };

            setInterval(function() {
                pillstreak.tick();
            }, CONF.TICK);

            this.runInstructions();
        },
        restart: function() {
            for (var i=0; i<this.$$cells.length; i++) {
                this.setCell(this.$$cells[i], {type: 'free', level: ''});
            }
            this.$game.classList.remove('lost');
            this.init();
        },

        info: function(text) {
            if (text) {
                this.$infoText.innerHTML = text;
                this.$info.classList.remove('hidden');
            } else {
                this.$info.classList.add('hidden');
            }
        },
        runInstructions: function() {
            this.instructionStep = 0;

            var i = setInterval(function() {
                var step = INSTRUCTIONS[pillstreak.instructionStep];
                if (step) {
                    pillstreak.info(step);
                    pillstreak.instructionStep++;
                } else {
                    pillstreak.info();
                    clearInterval(i);
                }
            }, 2000);
        },

        ticks: 0,
        tick: function() {
            this.ticks++;
            var inf = 0;
            var virii = document.querySelectorAll('[type=infection]');
            for (var i=0; i < virii.length; i++) {
                inf += parseInt(virii[i].getAttribute('level'), 10);
            }
            var thresh = 1.00 - (0.025 * inf);
            if (Math.random() > thresh) {
                var cell = this.getOccupiedCell('infection');
                this.q(cell, 'grow');
            }

            if (this.ticks % 10 === 0) {
                this.q(document.body, 'pulse');
            }

            if (this.lost) {
                this.$game.classList.add('lost');
                this.$restart.classList.remove('hidden');

                var pill = this.getOccupiedCell('pill');
                if (pill) {
                    this.setCell(pill, {type: 'infection'});
                } else {
                    var free = this.getFreeCell();
                    if (free) {
                        this.setCell(free, {type: 'infection', level: 1});
                    }
                }
            }
        },

        addPoints: function(points) {
            var cur = parseInt(this.$points.innerHTML, 10);
            this.$points.innerHTML = cur + points;

            var high = parseInt(this.$high.innerHTML, 10);
            this.$high.innerHTML = Math.max(high, cur + points);
        },
        loseHealth: function() {
            var cur = parseInt(this.$health.innerHTML, 10);
            this.$health.innerHTML = cur - 1;
            if (cur - 1 === 0) {
                // lost the game!
                this.lost = true;
                this.info("The infection has won...");
            }
        },

        getFreeCell: function() {
            var free = [];
            for (var i=0; i<this.$$cells.length; i++) {
                if (this.$$cells[i].getAttribute('type') === 'free') {
                    free.push(this.$$cells[i]);
                }
            }
            if (free.length > 0) {
                return free[ parseInt(free.length * Math.random(), 10) ];
            }
        },
        getOccupiedCell: function(type) {
            var cell = [];
            for (var i=0; i<this.$$cells.length; i++) {
                if (type && type === this.$$cells[i].getAttribute('type')) {
                    cell.push(this.$$cells[i]);
                } else if (!type && this.$$cells[i].getAttribute('type') !== 'free') {
                    cell.push(this.$$cells[i]);
                }
            }
            if (cell.length > 0) {
                return cell[ parseInt(cell.length * Math.random(), 10) ];
            }
        },
        setCell: function(cell, data) {
            var prop;
            for (prop in data) {
                cell.setAttribute(prop, data[prop]);
            }
        },
        setCellAt: function(row, col, data) {
            this.setCell(this.getCellAt(row, col), data);
        },

        getCellAt: function(row, col) {
            return document.querySelector(".cell[col='"+col+"'][row='"+row+"']");
        },

        getRow: function(row) {
            var cells = document.querySelectorAll(".cell[row='"+row+"']");
            cells.forEach = Array.prototype.forEach;
            return cells;
        },
        getColumn: function(col) {
            var cells = document.querySelectorAll(".cell[col='"+col+"']");
            cells.forEach = Array.prototype.forEach;
            return cells;
        },

        populateRandom: function(type) {
            type = type || (Math.random() > CONF.INFECTION_RATE ? 'pill' : 'infection');
            var cell = this.getFreeCell();
            if (cell) {
                cell.setAttribute('type', type);
                cell.setAttribute('level', 1);
            }
        },

        getNeighbor: function(cell, direction) {
            var row = parseInt(cell.getAttribute('row'), 10);
            var col = parseInt(cell.getAttribute('col'), 10);

            switch (direction) {
                case 'up':
                    row--;
                    break;
                case 'down':
                    row++;
                    break;
                case 'left':
                    col--;
                    break;
                case 'right':
                    col++;
                    break;
                default:
                    break;
            }

            if (row < 0 || row > 3 || col < 0 || col > 3) {
                return null;
            } else {
                return this.getCellAt(row, col);
            }
        },

        q: function(el, a, f, t) {
            var classes = a.split(' ');
            for (var i=0; i < classes.length; i++) {
                classes[i] = 'anim-' + classes[i];
                el.classList.add(classes[i]);
            }
            setTimeout(function() {
                if (f) {
                    f();
                }
                for (var i=0; i < classes.length; i++) {
                    el.classList.remove(classes[i]);
                }
            }, t || CONF.ANIM_SPEED);
        },

        moveCell: function(cell, other) {
            var first_row = cell.getAttribute('row');
            var first_col = cell.getAttribute('col');

            cell.setAttribute('row', other.getAttribute('row'));
            cell.setAttribute('col', other.getAttribute('col'));

            other.setAttribute('row', first_row);
            other.setAttribute('col', first_col);
        },

        mergeCells: function(cell, other, direction) {
            var level = parseInt(other.getAttribute('level'), 10);
            level += parseInt(cell.getAttribute('level'), 10);
            other.setAttribute('level', level);

            this.q(cell, 'merge-' + direction, function() {
                cell.setAttribute('type', 'free');
                cell.setAttribute('level', '');
            });
            this.q(other, 'grow');
        },

        fightCells: function(cell, other, direction) {
            var pill = parseInt(cell.getAttribute('level'), 10);
            var infection = parseInt(other.getAttribute('level'), 10);

            if (pill >= infection) {
                other.setAttribute('type', 'free');
                other.setAttribute('level', '');
                this.movePoints += 100 * infection;
                this.victories++;
            } else {
                this.mergeCells(cell, other, direction);
                this.loseHealth();
            }

            this.q(cell, 'consume-'+direction, function() {
                cell.setAttribute('type', 'free');
                cell.setAttribute('level', '');
            });
        },

        pendingShift: null,
        shiftAllCells: function(direction) {
            var neighbor;
            var grouper, groups;
            var shifted = false;
            if (this.shifting) {
                this.pendingShift = direction;
                return;
            }
            this.pendingShift = null;
            this.victories = 0;
            this.movePoints = 0;

            this.shifting = true;
            switch (direction) {
                case 'up':
                case 'down':
                    grouper = this.getRow;
                    break;
                case 'left':
                case 'right':
                    grouper = this.getColumn;
                    break;
                default:
                    break;
            }

            switch (direction) {
                case 'up':
                case 'left':
                    groups = [3, 2, 1, 0];
                    break;
                case 'down':
                case 'right':
                    groups = [0, 1, 2, 3];
                    break;
                default:
                    break;
            }

            function shiftGroup(cell) {
                if (CONF.DEBUG_SHIFT) {
                    console.log('shift', cell);
                    pillstreak.q(cell, 'highlight', function(){});
                }
                if (cell.getAttribute('type') !== 'free') {
                    neighbor = pillstreak.getNeighbor(cell, direction);
                    if (neighbor) {
                        if (neighbor.getAttribute('type') === 'free') {
                            pillstreak.moveCell(cell, neighbor);
                            shifted = true;
                        } else if (neighbor.getAttribute('type') === cell.getAttribute('type')) {
                            pillstreak.mergeCells(cell, neighbor, direction);
                            shifted = true;
                        } else if (cell.getAttribute('type') === 'pill') {
                            pillstreak.fightCells(cell, neighbor, direction);
                            shifted = true;
                        }
                    }
                }
            }

            function populateIfShifted() {
                if (pillstreak.victories > 0) {
                    if (pillstreak.victories > 1) {
                        pillstreak.info("BONUS x" + pillstreak.victories + "!");
                    }
                    pillstreak.addPoints(pillstreak.movePoints * pillstreak.victories);
                }

                if (shifted) {
                    pillstreak.populateRandom();
                }
                pillstreak.shifting = false;
                if (pillstreak.pendingShift) {
                    pillstreak.shiftAllCells(pillstreak.pendingShift);
                }
            }

            var t = 0;
            while (groups.length > 0) {
                var i = groups.pop();
                (function(i) {
                    setTimeout(function(){
                        grouper(i).forEach(shiftGroup);
                    }, CONF.SHIFT_SPEED * t);
                    t++;
                })(i);
            }
            setTimeout(populateIfShifted, CONF.SHIFT_SPEED * 5);
        },
    };
    return exports;
})();

window.pillstreak.init();
<commit_msg>Clear the bonus message after half a second<commit_after>/* global pillstreak */
window.pillstreak = (function() {
    var KEYS = {
        37: 'left',
        38: 'up',
        39: 'right',
        40: 'down',
    };

    var CONF = {
        ANIM_SPEED: 100,
        SHIFT_SPEED: 110,
        TICK: 100,
        INFECTION_RATE: 0.4,
        DEBUG_SHIFT: false,
    }

    var INSTRUCTIONS = [
        "You are not well.",
        "But, you are not powerless!",
        "Combine pills to form Good Habits.",
        "Avoid letting the infection spread.",
        "The stronger the infection...",
        "the better you'll have to be with your pills.",
        "Swipe or use arrow keys to move.",
        "Swipe or use arrow keys to move.",
        "Swipe or use arrow keys to move.",
    ];

    var exports = {
        init: function() {
            this.$game = document.querySelector('#game');
            this.$$cells = document.querySelectorAll(".cell");
            this.$points = document.querySelector('#points');
            this.$high = document.querySelector('#high');
            this.$health = document.querySelector('#health_points');
            this.$info = document.querySelector('#info');
            this.$infoText = document.querySelector('#info-text');
            this.$restart = document.querySelector('#restart');

            this.lost = false;
            this.$restart.classList.add('hidden');
            this.$points.innerHTML = '0';
            this.$health.innerHTML = '10';

            var i, row, col;
            for (i=0; i<this.$$cells.length; i++) {
                row = i % 4;
                col = parseInt(i / 4, 10);
                this.$$cells[i].setAttribute('type', 'free');
                this.$$cells[i].setAttribute('row', row);
                this.$$cells[i].setAttribute('col', col);
                this.$$cells[i].setAttribute('level', '');
            }

            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');
            pillstreak.populateRandom('infection');

            this.$game.focus();
            document.body.onkeyup = function(ev) {
                pillstreak.shiftAllCells(KEYS[ev.keyCode])
            };

            Hammer(document.body, {
                swipe: true,
                swipe_velocity: 0.1,
            }).on('swipeup swipedown swipeleft swiperight', function(ev) {
                pillstreak.shiftAllCells(ev.gesture.direction);
            });

            document.body.ontouchstart = function(ev) {
                ev.preventDefault();
            };

            setInterval(function() {
                pillstreak.tick();
            }, CONF.TICK);

            this.runInstructions();
        },
        restart: function() {
            for (var i=0; i<this.$$cells.length; i++) {
                this.setCell(this.$$cells[i], {type: 'free', level: ''});
            }
            this.$game.classList.remove('lost');
            this.init();
        },

        info: function(text, t) {
            if (text) {
                this.$infoText.innerHTML = text;
                this.$info.classList.remove('hidden');

                if (t) {
                    setTimeout(function() {
                        if (pillstreak.$infoText.innerHTML === text) {
                            pillstreak.info();
                        }
                    }, t);
                }
            } else {
                this.$info.classList.add('hidden');
            }
        },
        runInstructions: function() {
            this.instructionStep = 0;

            var i = setInterval(function() {
                var step = INSTRUCTIONS[pillstreak.instructionStep];
                if (step) {
                    pillstreak.info(step);
                    pillstreak.instructionStep++;
                } else {
                    pillstreak.info();
                    clearInterval(i);
                }
            }, 2000);
        },

        ticks: 0,
        tick: function() {
            this.ticks++;
            var inf = 0;
            var virii = document.querySelectorAll('[type=infection]');
            for (var i=0; i < virii.length; i++) {
                inf += parseInt(virii[i].getAttribute('level'), 10);
            }
            var thresh = 1.00 - (0.025 * inf);
            if (Math.random() > thresh) {
                var cell = this.getOccupiedCell('infection');
                this.q(cell, 'grow');
            }

            if (this.ticks % 10 === 0) {
                this.q(document.body, 'pulse');
            }

            if (this.lost) {
                this.$game.classList.add('lost');
                this.$restart.classList.remove('hidden');

                var pill = this.getOccupiedCell('pill');
                if (pill) {
                    this.setCell(pill, {type: 'infection'});
                } else {
                    var free = this.getFreeCell();
                    if (free) {
                        this.setCell(free, {type: 'infection', level: 1});
                    }
                }
            }
        },

        addPoints: function(points) {
            var cur = parseInt(this.$points.innerHTML, 10);
            this.$points.innerHTML = cur + points;

            var high = parseInt(this.$high.innerHTML, 10);
            this.$high.innerHTML = Math.max(high, cur + points);
        },
        loseHealth: function() {
            var cur = parseInt(this.$health.innerHTML, 10);
            this.$health.innerHTML = cur - 1;
            if (cur - 1 === 0) {
                // lost the game!
                this.lost = true;
                this.info("The infection has won...");
            }
        },

        getFreeCell: function() {
            var free = [];
            for (var i=0; i<this.$$cells.length; i++) {
                if (this.$$cells[i].getAttribute('type') === 'free') {
                    free.push(this.$$cells[i]);
                }
            }
            if (free.length > 0) {
                return free[ parseInt(free.length * Math.random(), 10) ];
            }
        },
        getOccupiedCell: function(type) {
            var cell = [];
            for (var i=0; i<this.$$cells.length; i++) {
                if (type && type === this.$$cells[i].getAttribute('type')) {
                    cell.push(this.$$cells[i]);
                } else if (!type && this.$$cells[i].getAttribute('type') !== 'free') {
                    cell.push(this.$$cells[i]);
                }
            }
            if (cell.length > 0) {
                return cell[ parseInt(cell.length * Math.random(), 10) ];
            }
        },
        setCell: function(cell, data) {
            var prop;
            for (prop in data) {
                cell.setAttribute(prop, data[prop]);
            }
        },
        setCellAt: function(row, col, data) {
            this.setCell(this.getCellAt(row, col), data);
        },

        getCellAt: function(row, col) {
            return document.querySelector(".cell[col='"+col+"'][row='"+row+"']");
        },

        getRow: function(row) {
            var cells = document.querySelectorAll(".cell[row='"+row+"']");
            cells.forEach = Array.prototype.forEach;
            return cells;
        },
        getColumn: function(col) {
            var cells = document.querySelectorAll(".cell[col='"+col+"']");
            cells.forEach = Array.prototype.forEach;
            return cells;
        },

        populateRandom: function(type) {
            type = type || (Math.random() > CONF.INFECTION_RATE ? 'pill' : 'infection');
            var cell = this.getFreeCell();
            if (cell) {
                cell.setAttribute('type', type);
                cell.setAttribute('level', 1);
            }
        },

        getNeighbor: function(cell, direction) {
            var row = parseInt(cell.getAttribute('row'), 10);
            var col = parseInt(cell.getAttribute('col'), 10);

            switch (direction) {
                case 'up':
                    row--;
                    break;
                case 'down':
                    row++;
                    break;
                case 'left':
                    col--;
                    break;
                case 'right':
                    col++;
                    break;
                default:
                    break;
            }

            if (row < 0 || row > 3 || col < 0 || col > 3) {
                return null;
            } else {
                return this.getCellAt(row, col);
            }
        },

        q: function(el, a, f, t) {
            var classes = a.split(' ');
            for (var i=0; i < classes.length; i++) {
                classes[i] = 'anim-' + classes[i];
                el.classList.add(classes[i]);
            }
            setTimeout(function() {
                if (f) {
                    f();
                }
                for (var i=0; i < classes.length; i++) {
                    el.classList.remove(classes[i]);
                }
            }, t || CONF.ANIM_SPEED);
        },

        moveCell: function(cell, other) {
            var first_row = cell.getAttribute('row');
            var first_col = cell.getAttribute('col');

            cell.setAttribute('row', other.getAttribute('row'));
            cell.setAttribute('col', other.getAttribute('col'));

            other.setAttribute('row', first_row);
            other.setAttribute('col', first_col);
        },

        mergeCells: function(cell, other, direction) {
            var level = parseInt(other.getAttribute('level'), 10);
            level += parseInt(cell.getAttribute('level'), 10);
            other.setAttribute('level', level);

            this.q(cell, 'merge-' + direction, function() {
                cell.setAttribute('type', 'free');
                cell.setAttribute('level', '');
            });
            this.q(other, 'grow');
        },

        fightCells: function(cell, other, direction) {
            var pill = parseInt(cell.getAttribute('level'), 10);
            var infection = parseInt(other.getAttribute('level'), 10);

            if (pill >= infection) {
                other.setAttribute('type', 'free');
                other.setAttribute('level', '');
                this.movePoints += 100 * infection;
                this.victories++;
            } else {
                this.mergeCells(cell, other, direction);
                this.loseHealth();
            }

            this.q(cell, 'consume-'+direction, function() {
                cell.setAttribute('type', 'free');
                cell.setAttribute('level', '');
            });
        },

        pendingShift: null,
        shiftAllCells: function(direction) {
            var neighbor;
            var grouper, groups;
            var shifted = false;
            if (this.shifting) {
                this.pendingShift = direction;
                return;
            }
            this.pendingShift = null;
            this.victories = 0;
            this.movePoints = 0;

            this.shifting = true;
            switch (direction) {
                case 'up':
                case 'down':
                    grouper = this.getRow;
                    break;
                case 'left':
                case 'right':
                    grouper = this.getColumn;
                    break;
                default:
                    break;
            }

            switch (direction) {
                case 'up':
                case 'left':
                    groups = [3, 2, 1, 0];
                    break;
                case 'down':
                case 'right':
                    groups = [0, 1, 2, 3];
                    break;
                default:
                    break;
            }

            function shiftGroup(cell) {
                if (CONF.DEBUG_SHIFT) {
                    console.log('shift', cell);
                    pillstreak.q(cell, 'highlight', function(){});
                }
                if (cell.getAttribute('type') !== 'free') {
                    neighbor = pillstreak.getNeighbor(cell, direction);
                    if (neighbor) {
                        if (neighbor.getAttribute('type') === 'free') {
                            pillstreak.moveCell(cell, neighbor);
                            shifted = true;
                        } else if (neighbor.getAttribute('type') === cell.getAttribute('type')) {
                            pillstreak.mergeCells(cell, neighbor, direction);
                            shifted = true;
                        } else if (cell.getAttribute('type') === 'pill') {
                            pillstreak.fightCells(cell, neighbor, direction);
                            shifted = true;
                        }
                    }
                }
            }

            function populateIfShifted() {
                if (pillstreak.victories > 0) {
                    if (pillstreak.victories > 1) {
                        pillstreak.info("BONUS x" + pillstreak.victories + "!", 500);
                    }
                    pillstreak.addPoints(pillstreak.movePoints * pillstreak.victories);
                }

                if (shifted) {
                    pillstreak.populateRandom();
                }
                pillstreak.shifting = false;
                if (pillstreak.pendingShift) {
                    pillstreak.shiftAllCells(pillstreak.pendingShift);
                }
            }

            var t = 0;
            while (groups.length > 0) {
                var i = groups.pop();
                (function(i) {
                    setTimeout(function(){
                        grouper(i).forEach(shiftGroup);
                    }, CONF.SHIFT_SPEED * t);
                    t++;
                })(i);
            }
            setTimeout(populateIfShifted, CONF.SHIFT_SPEED * 5);
        },
    };
    return exports;
})();

window.pillstreak.init();
<|endoftext|>


<commit_before>/**
 * @file Main entry point for application
 * @author Jason Wohlgemuth
 * @requires app
 * @requires router
 * @requires views/Home
**/
define(function(require) {
    'use strict';

    var Backbone   = require('backbone');
    var Marionette = require('backbone.marionette');
    var omaha    = require('app');
    var Router     = require('router');
    var Home       = require('views/Home');

    omaha.on('before:start', function() {
        omaha.info('Starting...');
        omaha.router = new Router();
    });
    omaha.on('start', function() {
        Backbone.history.start();
        omaha.info('Started!');
        omaha.getRegion().show(new Home());
    });
    if (typeof (define) === 'undefined') {
        //Not AMD ==> Bundled with Browserify
        document.addEventListener('DOMContentLoaded', function() {
            omaha.start();
        });
    } else {
        //AMD == > Bundled with r.js
        omaha.start();
    }
});
<commit_msg>Aligned = in main<commit_after>/**
 * @file Main entry point for application
 * @author Jason Wohlgemuth
 * @requires app
 * @requires router
 * @requires views/Home
**/
define(function(require) {
    'use strict';

    var Backbone   = require('backbone');
    var Marionette = require('backbone.marionette');
    var omaha      = require('app');
    var Router     = require('router');
    var Home       = require('views/Home');

    omaha.on('before:start', function() {
        omaha.info('Starting...');
        omaha.router = new Router();
    });
    omaha.on('start', function() {
        Backbone.history.start();
        omaha.info('Started!');
        omaha.getRegion().show(new Home());
    });
    if (typeof (define) === 'undefined') {
        //Not AMD ==> Bundled with Browserify
        document.addEventListener('DOMContentLoaded', function() {
            omaha.start();
        });
    } else {
        //AMD == > Bundled with r.js
        omaha.start();
    }
});
<|endoftext|>


<commit_before>const electron = require('electron')
// Module to control application life.
const {app, globalShortcut} = require('electron')

const {ipcMain} = require('electron')

// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

var path = require('path')
var iconPath = path.join(__dirname, '/listen1_chrome_extension/images/logo.png');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
let willQuitApp = false;
var windowState = { maximized: false }

const globalShortcutMapping = {
  'CmdOrCtrl+Alt+Left':'left',
  'CmdOrCtrl+Alt+Right':'right',
};

function initialTray(mainWindow) {
  const {app, Menu, Tray} = require('electron');

  let appIcon = null;

  var trayIconPath = path.join(__dirname, '/resources/logo_16.png');
  appTray = new Tray(trayIconPath);

  function toggleVisiable() {
    var isVisible = mainWindow.isVisible();
    if (isVisible) {
      mainWindow.hide();
    } else {
      mainWindow.show();
    }
  }
  const contextMenu = Menu.buildFromTemplate([
    {label: '显示/隐藏窗口',  click(){
      toggleVisiable();
    }},
    {label: '退出',  click() {
      app.quit();
    }},
  ]);
  //appTray.setToolTip('This is my application.');
  appTray.setContextMenu(contextMenu);
  appTray.on('click', function handleClicked () {
    toggleVisiable();
  });
}

function setKeyMapping(key, message) {
    const ret = globalShortcut.register(key, () => {
      mainWindow.webContents.send('globalShortcut', message);
    });
}

function enableGlobalShortcuts() {
  // initial global shortcuts
  for (let key in globalShortcutMapping){
    setKeyMapping(key, globalShortcutMapping[key]);
  }
}

function disableGlobalShortcuts() {
  for (let key in globalShortcutMapping){
    globalShortcut.unregister(key);
  }

  globalShortcut.unregisterAll()
}

let floatingWindow;
const createFloatingWindow = function () {
  const electron = require('electron');
  const BrowserWindow = electron.BrowserWindow;
  const display = electron.screen.getPrimaryDisplay();
  if (!floatingWindow) {
    floatingWindow = new BrowserWindow({
      width: 1000,
      height: 80,
      titleBarStyle: 'hide',
      transparent: true,
      frame: false,
      resizable: false,
      hasShadow: false,
      alwaysOnTop:true,
      visibleOnAllWorkspaces: true,
      webPreferences: {
        nodeIntegration: true
      }
    });
    floatingWindow.setPosition(floatingWindow.getPosition()[0], display.bounds.height - 150);
    floatingWindow.setSkipTaskbar(true);
    floatingWindow.loadURL(`file://${__dirname}/floatingWindow.html`);
    floatingWindow.setAlwaysOnTop(true, 'floating');
    floatingWindow.on('closed', function () { floatingWindow = null })
  }
  floatingWindow.showInactive();
};

function createWindow() {

  const session = require('electron').session;

  const filter = {
    urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://i.y.qq.com/*", "*://c.y.qq.com/*", "*://*.kugou.com/*", "*://*.kuwo.cn/*", "*://*.bilibili.com/*", "*://*.migu.cn/*", "*://*.githubusercontent.com/*",
      "https://listen1.github.io/listen1/callback.html?code=*"]
  };

  session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) {
    if(details.url.startsWith("https://listen1.github.io/listen1/callback.html?code=")){
      const url = details.url;
      const code = url.split('=')[1];
      mainWindow.webContents.executeJavaScript('Github.handleCallback("'+code+'");');
    }
    else {
      hack_referer_header(details);
    }
    callback({cancel: false, requestHeaders: details.requestHeaders});
  });

  var transparent = false;
  if (process.platform == 'darwin') {
    transparent = true;
  }
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 670,
    webPreferences: {'nodeIntegration': true},
    icon: iconPath,
    titleBarStyle: 'hiddenInset',
    transparent: transparent,
    vibrancy: 'light',
    frame: false,
    hasShadow: true
  });

  // mainWindow.webContents.openDevTools();

  mainWindow.on('close', (e) => {
    if (willQuitApp) {
      /* the user tried to quit the app */
      mainWindow = null;
    } else {
      /* the user only tried to close the window */
      //if (process.platform != 'linux') {
        e.preventDefault();
        mainWindow.hide();
        //mainWindow.minimize();
      //}

    }
  });

  // and load the index.html of the app.
  var ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36';
  mainWindow.loadURL(`file://${__dirname}/listen1_chrome_extension/listen1.html`, {userAgent: ua})

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })

  // define global menu content, also add support for cmd+c and cmd+v shortcuts
  var template = [{
      label: "Application",
      submenu: [
          { label: "About Application", selector: "orderFrontStandardAboutPanel:" },
          { type: "separator" },
          { label: "Quit", accelerator: "Command+Q", click: function() { app.quit(); }}
      ]}, {
      label: "Edit",
      submenu: [
          { label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
          { label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
          { type: "separator" },
          { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
          { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
          { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
          { label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
      ]}
  ];

  mainWindow.setMenu(null);

  electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template));

  initialTray(mainWindow);
}

function hack_referer_header(details) {
    let replace_referer = true;
    let replace_origin = true;
    let add_referer = true;
    let add_origin = true;
    var referer_value = '';

    if (details.url.indexOf("://music.163.com/") != -1) {
        referer_value = "http://music.163.com/";
    }
    if (details.url.indexOf("://gist.githubusercontent.com/") != -1) {
        referer_value = "https://gist.githubusercontent.com/";
    }

    if (details.url.indexOf("api.xiami.com/") != -1 || details.url.indexOf('.xiami.com/song/playlist/id/') != -1) {
        referer_value = "https://www.xiami.com/";
    }

    if ((details.url.indexOf("y.qq.com/") != -1) ||
        (details.url.indexOf("qqmusic.qq.com/") != -1) ||
        (details.url.indexOf("music.qq.com/") != -1) ||
        (details.url.indexOf("imgcache.qq.com/") != -1)) {
        referer_value = "http://y.qq.com/";
    }
    if (details.url.indexOf(".kugou.com/") != -1) {
        referer_value = "http://www.kugou.com/";
    }
    if (details.url.indexOf(".kuwo.cn/") != -1) {
        referer_value = "http://www.kuwo.cn/";
    }
    if (details.url.indexOf(".bilibili.com/") != -1) {
        referer_value = "http://www.bilibili.com/";
        replace_origin = false;
        add_origin = false;
    }
    if (details.url.indexOf('.migu.cn') !== -1) {
        referer_value = 'http://music.migu.cn/v3/music/player/audio?from=migu';
    }

    var isRefererSet = false;
    var isOriginSet = false;
    var headers = details.requestHeaders,
        blockingResponse = {};

    for (var i = 0, l = headers.length; i < l; ++i) {
        if (replace_referer && (headers[i].name == 'Referer') && (referer_value != '')) {
            headers[i].value = referer_value;
            isRefererSet = true;
        }
        if (replace_origin && (headers[i].name == 'Origin') && (referer_value != '')) {
            headers[i].value = referer_value;
            isOriginSet = true;
        }
    }

    if (add_referer && (!isRefererSet) && (referer_value != '')) {
        headers["Referer"] = referer_value;
    }

    if (add_origin && (!isOriginSet) && (referer_value != '')) {
        headers["Origin"] = referer_value;
    }

    details.requestHeaders = headers;
};

ipcMain.on('currentLyric', (event, arg) => {
  if (floatingWindow && floatingWindow !== null) {
    floatingWindow.webContents.send('currentLyric', arg);
  }
})

ipcMain.on('control', (event, arg) => {
  // console.log(arg);
  if(arg == 'enable_global_shortcut') {
    enableGlobalShortcuts();
  }
  else if(arg == 'disable_global_shortcut') {
    disableGlobalShortcuts();
  }
  else if (arg == 'enable_lyric_floating_window') {
    createFloatingWindow();
  }
  else if (arg == 'disable_lyric_floating_window') {
    if (floatingWindow) {
      floatingWindow.hide();
    }
  }
  else if(arg == 'window_min') {
    mainWindow.minimize();
  }
  else if(arg == 'window_max') {
    if(windowState.maximized == true) {
        windowState.maximized = false;
        mainWindow.unmaximize();
      } else {
        windowState.maximized = true;
        mainWindow.maximize();
      }
  }
  else if(arg == 'window_close') {
    mainWindow.close();
  }
  // event.sender.send('asynchronous-reply', 'pong')
})

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  app.quit()
} else {
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    // Someone tried to run a second instance, we should focus our window.
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
  })

  // Create myWindow, load the rest of the app, etc...
  app.on('ready', () => {
    createWindow()
  })
}

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

/* 'activate' is emitted when the user clicks the Dock icon (OS X) */
app.on('activate', () => mainWindow.show());

/* 'before-quit' is emitted when Electron receives
 * the signal to exit and wants to start closing windows */
app.on('before-quit', () => willQuitApp = true);

app.on('will-quit', () => {
 disableGlobalShortcuts();
})

<commit_msg>add play/pause global shortcuts<commit_after>const electron = require('electron')
// Module to control application life.
const {app, globalShortcut} = require('electron')

const {ipcMain} = require('electron')

// Module to create native browser window.
const BrowserWindow = electron.BrowserWindow

var path = require('path')
var iconPath = path.join(__dirname, '/listen1_chrome_extension/images/logo.png');

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
let willQuitApp = false;
var windowState = { maximized: false }

const globalShortcutMapping = {
  'CmdOrCtrl+Alt+Left':'left',
  'CmdOrCtrl+Alt+Right':'right',
  'CmdOrCtrl+Alt+Space':'space',
};

function initialTray(mainWindow) {
  const {app, Menu, Tray} = require('electron');

  let appIcon = null;

  var trayIconPath = path.join(__dirname, '/resources/logo_16.png');
  appTray = new Tray(trayIconPath);

  function toggleVisiable() {
    var isVisible = mainWindow.isVisible();
    if (isVisible) {
      mainWindow.hide();
    } else {
      mainWindow.show();
    }
  }
  const contextMenu = Menu.buildFromTemplate([
    {label: '显示/隐藏窗口',  click(){
      toggleVisiable();
    }},
    {label: '退出',  click() {
      app.quit();
    }},
  ]);
  //appTray.setToolTip('This is my application.');
  appTray.setContextMenu(contextMenu);
  appTray.on('click', function handleClicked () {
    toggleVisiable();
  });
}

function setKeyMapping(key, message) {
    const ret = globalShortcut.register(key, () => {
      mainWindow.webContents.send('globalShortcut', message);
    });
}

function enableGlobalShortcuts() {
  // initial global shortcuts
  for (let key in globalShortcutMapping){
    setKeyMapping(key, globalShortcutMapping[key]);
  }
}

function disableGlobalShortcuts() {
  for (let key in globalShortcutMapping){
    globalShortcut.unregister(key);
  }

  globalShortcut.unregisterAll()
}

let floatingWindow;
const createFloatingWindow = function () {
  const electron = require('electron');
  const BrowserWindow = electron.BrowserWindow;
  const display = electron.screen.getPrimaryDisplay();
  if (!floatingWindow) {
    floatingWindow = new BrowserWindow({
      width: 1000,
      height: 80,
      titleBarStyle: 'hide',
      transparent: true,
      frame: false,
      resizable: false,
      hasShadow: false,
      alwaysOnTop:true,
      visibleOnAllWorkspaces: true,
      webPreferences: {
        nodeIntegration: true
      }
    });
    floatingWindow.setPosition(floatingWindow.getPosition()[0], display.bounds.height - 150);
    floatingWindow.setSkipTaskbar(true);
    floatingWindow.loadURL(`file://${__dirname}/floatingWindow.html`);
    floatingWindow.setAlwaysOnTop(true, 'floating');
    floatingWindow.on('closed', function () { floatingWindow = null })
  }
  floatingWindow.showInactive();
};

function createWindow() {

  const session = require('electron').session;

  const filter = {
    urls: ["*://music.163.com/*", "*://*.xiami.com/*", "*://i.y.qq.com/*", "*://c.y.qq.com/*", "*://*.kugou.com/*", "*://*.kuwo.cn/*", "*://*.bilibili.com/*", "*://*.migu.cn/*", "*://*.githubusercontent.com/*",
      "https://listen1.github.io/listen1/callback.html?code=*"]
  };

  session.defaultSession.webRequest.onBeforeSendHeaders(filter, function(details, callback) {
    if(details.url.startsWith("https://listen1.github.io/listen1/callback.html?code=")){
      const url = details.url;
      const code = url.split('=')[1];
      mainWindow.webContents.executeJavaScript('Github.handleCallback("'+code+'");');
    }
    else {
      hack_referer_header(details);
    }
    callback({cancel: false, requestHeaders: details.requestHeaders});
  });

  var transparent = false;
  if (process.platform == 'darwin') {
    transparent = true;
  }
  // Create the browser window.
  mainWindow = new BrowserWindow({
    width: 1000,
    height: 670,
    webPreferences: {'nodeIntegration': true},
    icon: iconPath,
    titleBarStyle: 'hiddenInset',
    transparent: transparent,
    vibrancy: 'light',
    frame: false,
    hasShadow: true
  });

  // mainWindow.webContents.openDevTools();

  mainWindow.on('close', (e) => {
    if (willQuitApp) {
      /* the user tried to quit the app */
      mainWindow = null;
    } else {
      /* the user only tried to close the window */
      //if (process.platform != 'linux') {
        e.preventDefault();
        mainWindow.hide();
        //mainWindow.minimize();
      //}

    }
  });

  // and load the index.html of the app.
  var ua = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36';
  mainWindow.loadURL(`file://${__dirname}/listen1_chrome_extension/listen1.html`, {userAgent: ua})

  // Open the DevTools.
  // mainWindow.webContents.openDevTools()

  // Emitted when the window is closed.
  mainWindow.on('closed', function () {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null
  })

  // define global menu content, also add support for cmd+c and cmd+v shortcuts
  var template = [{
      label: "Application",
      submenu: [
          { label: "About Application", selector: "orderFrontStandardAboutPanel:" },
          { type: "separator" },
          { label: "Quit", accelerator: "Command+Q", click: function() { app.quit(); }}
      ]}, {
      label: "Edit",
      submenu: [
          { label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:" },
          { label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:" },
          { type: "separator" },
          { label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:" },
          { label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:" },
          { label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:" },
          { label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:" }
      ]}
  ];

  mainWindow.setMenu(null);

  electron.Menu.setApplicationMenu(electron.Menu.buildFromTemplate(template));

  initialTray(mainWindow);
}

function hack_referer_header(details) {
    let replace_referer = true;
    let replace_origin = true;
    let add_referer = true;
    let add_origin = true;
    var referer_value = '';

    if (details.url.indexOf("://music.163.com/") != -1) {
        referer_value = "http://music.163.com/";
    }
    if (details.url.indexOf("://gist.githubusercontent.com/") != -1) {
        referer_value = "https://gist.githubusercontent.com/";
    }

    if (details.url.indexOf("api.xiami.com/") != -1 || details.url.indexOf('.xiami.com/song/playlist/id/') != -1) {
        referer_value = "https://www.xiami.com/";
    }

    if ((details.url.indexOf("y.qq.com/") != -1) ||
        (details.url.indexOf("qqmusic.qq.com/") != -1) ||
        (details.url.indexOf("music.qq.com/") != -1) ||
        (details.url.indexOf("imgcache.qq.com/") != -1)) {
        referer_value = "http://y.qq.com/";
    }
    if (details.url.indexOf(".kugou.com/") != -1) {
        referer_value = "http://www.kugou.com/";
    }
    if (details.url.indexOf(".kuwo.cn/") != -1) {
        referer_value = "http://www.kuwo.cn/";
    }
    if (details.url.indexOf(".bilibili.com/") != -1) {
        referer_value = "http://www.bilibili.com/";
        replace_origin = false;
        add_origin = false;
    }
    if (details.url.indexOf('.migu.cn') !== -1) {
        referer_value = 'http://music.migu.cn/v3/music/player/audio?from=migu';
    }

    var isRefererSet = false;
    var isOriginSet = false;
    var headers = details.requestHeaders,
        blockingResponse = {};

    for (var i = 0, l = headers.length; i < l; ++i) {
        if (replace_referer && (headers[i].name == 'Referer') && (referer_value != '')) {
            headers[i].value = referer_value;
            isRefererSet = true;
        }
        if (replace_origin && (headers[i].name == 'Origin') && (referer_value != '')) {
            headers[i].value = referer_value;
            isOriginSet = true;
        }
    }

    if (add_referer && (!isRefererSet) && (referer_value != '')) {
        headers["Referer"] = referer_value;
    }

    if (add_origin && (!isOriginSet) && (referer_value != '')) {
        headers["Origin"] = referer_value;
    }

    details.requestHeaders = headers;
};

ipcMain.on('currentLyric', (event, arg) => {
  if (floatingWindow && floatingWindow !== null) {
    floatingWindow.webContents.send('currentLyric', arg);
  }
})

ipcMain.on('control', (event, arg) => {
  // console.log(arg);
  if(arg == 'enable_global_shortcut') {
    enableGlobalShortcuts();
  }
  else if(arg == 'disable_global_shortcut') {
    disableGlobalShortcuts();
  }
  else if (arg == 'enable_lyric_floating_window') {
    createFloatingWindow();
  }
  else if (arg == 'disable_lyric_floating_window') {
    if (floatingWindow) {
      floatingWindow.hide();
    }
  }
  else if(arg == 'window_min') {
    mainWindow.minimize();
  }
  else if(arg == 'window_max') {
    if(windowState.maximized == true) {
        windowState.maximized = false;
        mainWindow.unmaximize();
      } else {
        windowState.maximized = true;
        mainWindow.maximize();
      }
  }
  else if(arg == 'window_close') {
    mainWindow.close();
  }
  // event.sender.send('asynchronous-reply', 'pong')
})

const gotTheLock = app.requestSingleInstanceLock()

if (!gotTheLock) {
  app.quit()
} else {
  app.on('second-instance', (event, commandLine, workingDirectory) => {
    // Someone tried to run a second instance, we should focus our window.
    if (mainWindow) {
      if (mainWindow.isMinimized()) mainWindow.restore()
      mainWindow.focus()
    }
  })

  // Create myWindow, load the rest of the app, etc...
  app.on('ready', () => {
    createWindow()
  })
}

// Quit when all windows are closed.
app.on('window-all-closed', function () {
  // On OS X it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

/* 'activate' is emitted when the user clicks the Dock icon (OS X) */
app.on('activate', () => mainWindow.show());

/* 'before-quit' is emitted when Electron receives
 * the signal to exit and wants to start closing windows */
app.on('before-quit', () => willQuitApp = true);

app.on('will-quit', () => {
 disableGlobalShortcuts();
})

<|endoftext|>


<commit_before>'use strict';

const {
  app,
  Menu,
  Tray,
  BrowserWindow,
  globalShortcut,
  ipcMain,
  clipboard,
  dialog,
  shell } = require('electron');

const path = require('path');

let mainWindow    = null;
let tray          = null;
let updateOffered = false;

// Hide the icon from the dock if the OS has it.
if (app.dock) {
  app.dock.hide();
}

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    frame: false,
    height: 396,
    width: 300,
    backgroundColor: '#2B2F3B',
    resizable: false,
    center: true,
    skipTaskbar: true,
    show: false,
    title: 'Brownie'
  });

  // The trigger used to show/hide the app window.
  // TODO: allow user to set a custom shortcut.
  globalShortcut.register('Alt+Space', () => {
    if (mainWindow.isVisible()) {
      if (app.hide) {
        // NOTE: to get focus back to the previous window on MacOS we need to
        // hide the app not only the window.
        app.hide();
      } else {
        // NOTE: Windows doesn't have app.hide method, but combination of
        // window.blur and window.hide does the same thing.
        mainWindow.blur();
        mainWindow.hide()
      }
    } else {
      mainWindow.show();
    }
  });

  if (process.platform === 'darwin') {
    tray = new Tray(path.join(__dirname, 'img', 'iconTemplate.png'));
  } else {
    tray = new Tray(path.join(__dirname, 'img', 'iconHighlight.png'));
  }

  const contextMenu = Menu.buildFromTemplate([
    { label: 'Clear clipboard history', click(item, focusedWindow) {
      mainWindow.webContents.send('clearClipboardHistory');
    }},
    { type: 'separator' },
    { label: 'Quit Olden', click(item, focusedWindow) {
      app.quit();
    }}
  ]);

  tray.setToolTip('Olden')
  tray.setContextMenu(contextMenu)

  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.setVisibleOnAllWorkspaces(true);
  // TODO: execute the line below based on the input argument value.
  // mainWindow.webContents.openDevTools();

  ipcMain.on('hideWindow', (event) => {
    if (app.hide) {
        app.hide();
      } else {
        mainWindow.blur();
        mainWindow.hide()
      }
  });

  ipcMain.on('offer-update', (event, data) => {
    if (!updateOffered) {
      dialog.showMessageBox({
        type:      'question',
        buttons:   [ 'Cancel', 'Download' ],
        defaultId: 0,
        title:     'A newer version of Olden is available',
        message:   'Would you like to download the update?'
      }, (response) => {
        if (response === 1) {
          shell.openExternal(data.url);
        }

        updateOffered = true;
      });
    }
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On MacOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
<commit_msg>Updates window title<commit_after>'use strict';

const {
  app,
  Menu,
  Tray,
  BrowserWindow,
  globalShortcut,
  ipcMain,
  clipboard,
  dialog,
  shell } = require('electron');

const path = require('path');

let mainWindow    = null;
let tray          = null;
let updateOffered = false;

// Hide the icon from the dock if the OS has it.
if (app.dock) {
  app.dock.hide();
}

app.on('ready', () => {
  mainWindow = new BrowserWindow({
    frame: false,
    height: 396,
    width: 300,
    backgroundColor: '#2B2F3B',
    resizable: false,
    center: true,
    skipTaskbar: true,
    show: false,
    title: 'Olden'
  });

  // The trigger used to show/hide the app window.
  // TODO: allow user to set a custom shortcut.
  globalShortcut.register('Alt+Space', () => {
    if (mainWindow.isVisible()) {
      if (app.hide) {
        // NOTE: to get focus back to the previous window on MacOS we need to
        // hide the app not only the window.
        app.hide();
      } else {
        // NOTE: Windows doesn't have app.hide method, but combination of
        // window.blur and window.hide does the same thing.
        mainWindow.blur();
        mainWindow.hide()
      }
    } else {
      mainWindow.show();
    }
  });

  if (process.platform === 'darwin') {
    tray = new Tray(path.join(__dirname, 'img', 'iconTemplate.png'));
  } else {
    tray = new Tray(path.join(__dirname, 'img', 'iconHighlight.png'));
  }

  const contextMenu = Menu.buildFromTemplate([
    { label: 'Clear clipboard history', click(item, focusedWindow) {
      mainWindow.webContents.send('clearClipboardHistory');
    }},
    { type: 'separator' },
    { label: 'Quit Olden', click(item, focusedWindow) {
      app.quit();
    }}
  ]);

  tray.setToolTip('Olden')
  tray.setContextMenu(contextMenu)

  mainWindow.loadURL('file://' + __dirname + '/index.html');
  mainWindow.setVisibleOnAllWorkspaces(true);
  // TODO: execute the line below based on the input argument value.
  // mainWindow.webContents.openDevTools();

  ipcMain.on('hideWindow', (event) => {
    if (app.hide) {
        app.hide();
      } else {
        mainWindow.blur();
        mainWindow.hide()
      }
  });

  ipcMain.on('offer-update', (event, data) => {
    if (!updateOffered) {
      dialog.showMessageBox({
        type:      'question',
        buttons:   [ 'Cancel', 'Download' ],
        defaultId: 0,
        title:     'A newer version of Olden is available',
        message:   'Would you like to download the update?'
      }, (response) => {
        if (response === 1) {
          shell.openExternal(data.url);
        }

        updateOffered = true;
      });
    }
  });
});

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On MacOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit();
  }
});
<|endoftext|>


<commit_before>var app = require('electron').app; // Module to control application life.
var BrowserWindow = require('electron').BrowserWindow; // Module to create native browser window.
var autoUpdater = require('./autoUpdater');
var path = require("path");
var fs = require("fs");
var createDefaultMenu = require('./menu.js');
var proxyWindowEvents = require('./proxyWindowEvents');

require('electron-debug')({
    showDevTools: false
});

var electronSettings = JSON.parse(fs.readFileSync(
  path.join(__dirname, "electronSettings.json"), "utf-8"));

var checkForUpdates;
if (electronSettings.updateFeedUrl) {
  autoUpdater.setFeedURL(electronSettings.updateFeedUrl + '?version=' + electronSettings.version);
  autoUpdater.checkForUpdates();
  checkForUpdates = function() {
    autoUpdater.checkForUpdates(true /* userTriggered */);
  };
}

var launchUrl = electronSettings.rootUrl;
if (electronSettings.launchPath) {
  launchUrl += electronSettings.launchPath;
}

var windowOptions = {
  width: electronSettings.width || 800,
  height: electronSettings.height || 600,
  resizable: true,
  frame: true,
  /**
   * Disable Electron's Node integration so that browser dependencies like `moment` will load themselves
   * like normal i.e. into the window rather than into modules, and also to prevent untrusted client
   * code from having access to the process and file system:
   *  - https://github.com/atom/electron/issues/254
   *  - https://github.com/atom/electron/issues/1753
   */
  webPreferences: {
    nodeIntegration: false,
    // See comments at the top of `preload.js`.
    preload: path.join(__dirname, 'preload.js')
  }
};

if (electronSettings.resizable === false){
  windowOptions.resizable = false;
}

if (electronSettings['title-bar-style']) {
  windowOptions['title-bar-style'] = electronSettings['title-bar-style'];
}

if (electronSettings.minWidth) {
  windowOptions.minWidth = electronSettings.minWidth;
}

if (electronSettings.maxWidth) {
  windowOptions.maxWidth = electronSettings.maxWidth;
}

if (electronSettings.minHeight) {
  windowOptions.minHeight = electronSettings.minHeight;
}

if (electronSettings.maxHeight) {
  windowOptions.maxHeight = electronSettings.maxHeight;
}

if (electronSettings.frame === false){
  windowOptions.frame = false;
}

// Keep a global reference of the window object so that it won't be garbage collected
// and the window closed.
var mainWindow = null;
var getMainWindow = function() {
  return mainWindow;
};

// Unfortunately, we must set the menu before the application becomes ready and so before the main
// window is available to be passed directly to `createDefaultMenu`.
createDefaultMenu(app, getMainWindow, checkForUpdates);

app.on("ready", function(){
  mainWindow = new BrowserWindow(windowOptions);
  proxyWindowEvents(mainWindow);

  // Hide the main window instead of closing it, so that we can bring it back
  // more quickly.
  mainWindow.on('close', hideInsteadofClose);

  mainWindow.focus();
  mainWindow.loadURL(launchUrl);
});

var hideInsteadofClose = function(e) {
  this.hide();
  e.preventDefault();
};

app.on("before-quit", function(){
  // We need to remove our close event handler from the main window,
  // otherwise the app will not quit.
  mainWindow.removeListener('close', hideInsteadofClose);
});

app.on("activate", function(){
  // Show the main window when the customer clicks on the app icon.
  if (!mainWindow.isVisible()) mainWindow.show();
});
<commit_msg>Be explicit abot what `this` is<commit_after>var app = require('electron').app; // Module to control application life.
var BrowserWindow = require('electron').BrowserWindow; // Module to create native browser window.
var autoUpdater = require('./autoUpdater');
var path = require("path");
var fs = require("fs");
var createDefaultMenu = require('./menu.js');
var proxyWindowEvents = require('./proxyWindowEvents');

require('electron-debug')({
    showDevTools: false
});

var electronSettings = JSON.parse(fs.readFileSync(
  path.join(__dirname, "electronSettings.json"), "utf-8"));

var checkForUpdates;
if (electronSettings.updateFeedUrl) {
  autoUpdater.setFeedURL(electronSettings.updateFeedUrl + '?version=' + electronSettings.version);
  autoUpdater.checkForUpdates();
  checkForUpdates = function() {
    autoUpdater.checkForUpdates(true /* userTriggered */);
  };
}

var launchUrl = electronSettings.rootUrl;
if (electronSettings.launchPath) {
  launchUrl += electronSettings.launchPath;
}

var windowOptions = {
  width: electronSettings.width || 800,
  height: electronSettings.height || 600,
  resizable: true,
  frame: true,
  /**
   * Disable Electron's Node integration so that browser dependencies like `moment` will load themselves
   * like normal i.e. into the window rather than into modules, and also to prevent untrusted client
   * code from having access to the process and file system:
   *  - https://github.com/atom/electron/issues/254
   *  - https://github.com/atom/electron/issues/1753
   */
  webPreferences: {
    nodeIntegration: false,
    // See comments at the top of `preload.js`.
    preload: path.join(__dirname, 'preload.js')
  }
};

if (electronSettings.resizable === false){
  windowOptions.resizable = false;
}

if (electronSettings['title-bar-style']) {
  windowOptions['title-bar-style'] = electronSettings['title-bar-style'];
}

if (electronSettings.minWidth) {
  windowOptions.minWidth = electronSettings.minWidth;
}

if (electronSettings.maxWidth) {
  windowOptions.maxWidth = electronSettings.maxWidth;
}

if (electronSettings.minHeight) {
  windowOptions.minHeight = electronSettings.minHeight;
}

if (electronSettings.maxHeight) {
  windowOptions.maxHeight = electronSettings.maxHeight;
}

if (electronSettings.frame === false){
  windowOptions.frame = false;
}

// Keep a global reference of the window object so that it won't be garbage collected
// and the window closed.
var mainWindow = null;
var getMainWindow = function() {
  return mainWindow;
};

// Unfortunately, we must set the menu before the application becomes ready and so before the main
// window is available to be passed directly to `createDefaultMenu`.
createDefaultMenu(app, getMainWindow, checkForUpdates);

app.on("ready", function(){
  mainWindow = new BrowserWindow(windowOptions);
  proxyWindowEvents(mainWindow);

  // Hide the main window instead of closing it, so that we can bring it back
  // more quickly.
  mainWindow.on('close', hideInsteadofClose);

  mainWindow.focus();
  mainWindow.loadURL(launchUrl);
});

var hideInsteadofClose = function(e) {
  mainWindow.hide();
  e.preventDefault();
};

app.on("before-quit", function(){
  // We need to remove our close event handler from the main window,
  // otherwise the app will not quit.
  mainWindow.removeListener('close', hideInsteadofClose);
});

app.on("activate", function(){
  // Show the main window when the customer clicks on the app icon.
  if (!mainWindow.isVisible()) mainWindow.show();
});
<|endoftext|>


<commit_before>
var inherits = require('util').inherits,
    inspect  = require('util').inspect,
    out      = process.stdout

// http://stackoverflow.com/a/5450113
var repeat = function (pattern, count) {
  if (count < 1) return '';
  var result = ''
  while (count > 1) {
    if (count & 1) result += pattern;
    count >>= 1, pattern += pattern
  }
  return result + pattern
}

var INDENT = 2

var _ind = 0,
    _i   = function () { return repeat(' ', _ind) },
    _w   = function (s) { out.write(_i() + s) },
    _win = function (s) {
      // Indent and write
      _w(s); _ind += INDENT
    },
    _wout = function (s) { _ind -= INDENT; _w(s) }

// Nodes ----------------------------------------------------------------------

var Node = function () {}
Node.prototype.print = function () { out.write(inspect(this)) }

var Let = function Let(name, typepath) {
  this.name = name.trim()
  this.typepath = typepath
}
inherits(Let, Node)
Let.prototype.print    = function () { _w(this.toString()+"\n") }
Let.prototype.toString = function () { return this.name }

// Quick and dirty clone of Let
var Var = Let.bind({})
inherits(Var, Node)
Var.prototype.print    = Let.prototype.print
Var.prototype.toString = Let.prototype.toString

var Expression = function () {}
inherits(Expression, Node)

var Group = function Group(expr) {
  this.expr = expr
}
inherits(Group, Expression)
Group.prototype.toString = function () { return '('+this.expr.toString()+')' }

var Binary = function (lexpr, op, rexpr) {
  this.lexpr = lexpr
  this.op    = op
  this.rexpr = rexpr
}
inherits(Binary, Expression)
Binary.prototype.print = function () { out.write(this.toString()) }
Binary.prototype.toString = function () {
  return this.lexpr.toString()+' '+this.op+' '+this.rexpr.toString()
}

var Literal = function Literal(value) {
  this.value = value
}
inherits(Literal, Node)
Literal.prototype.print    = function () { out.write(this.toString()) }
Literal.prototype.toString = function () { return this.value.toString() }

var Assignment = function (type, lvalue, rvalue) {
  this.type   = type
  this.lvalue = lvalue
  this.rvalue = rvalue
}
inherits(Assignment, Node)
Assignment.prototype.print = function () {
  var type = (this.type != 'path') ? (this.type+' ') : ''
  _w(type + this.lvalue.toString()+' = ')
  if (this.rvalue) {
    // _ind += INDENT
    this.rvalue.print()
    // _ind -= INDENT
  }
}

var Path = function (name) { this.name = name }
inherits(Path, Node)
Path.prototype.toString = function () { return this.name }

var Function = function (args, block) {
  this.args  = args
  this.block = block
}
inherits(Function, Node)
Function.prototype.print = function () {
  var args = this.args.map(function (arg) {
    var ret = arg.name
    if (arg.type) {
      ret += ': '+arg.type
    }
    return ret
  }).join(', ')
  out.write('func ('+args+') ')
  this.block.print()
}

var Call = function (args) {
  this.args = args
}
inherits(Call, Node)
Call.prototype.toString = function () {
  return '('+this.args.map(function (arg) { return arg.toString() }).join(', ')+')'
}

var If = function (cond, block) {
  this.cond  = cond
  this.block = block
}
inherits(If, Node)
If.prototype.print = function () {
  var cond = this.cond.toString()
  _w("if "+cond+" ")
  this.block.print()
}

var While = function (expr, block) {
  this.expr  = expr // Loop expression
  this.block = block
}
inherits(While, Node)
While.prototype.print = function () {
  _w("while(" + this.expr + ") ")
  this.block.print()
}

var For = function (init, cond, after, block) {
  this.init  = init // Initialization
  this.cond  = cond // Condition
  this.after = after // Afterthought
  this.block = block
}
inherits(For, Node)
For.prototype.print = function () {
  _w("for ")
  // Don't indent while we're writing out these statements
  var i = _ind
  _ind = 0;
  this.init.print();  out.write('; ')
  this.cond.print();  out.write('; ')
  this.after.print(); out.write(' ')
  // Restore indent and print the block
  _ind = i;
  this.block.print()
}

var Chain = function (name, tail) {
  this.name = name
  this.tail = tail
}
inherits(Chain, Node)
Chain.prototype.toString = function () {
  var base = this.name
  this.tail.forEach(function (expr) {
    base += expr.toString()
  })
  return base
}
Chain.prototype.print = function () { out.write(this.toString()) }

var Return = function (expr) {
  this.expr = expr
}
inherits(Return, Node)
Return.prototype.print    = function () { _w(this.toString()) }
Return.prototype.toString = function () { return 'return '+this.expr.toString() }

var Root = function (statements) {
  this.statements = statements
}
inherits(Root, Node)
Root.prototype.print = function() {
  _win("root {\n")
  this.statements.forEach(function (stmt) {
    stmt.print()
    out.write("\n")
  })
  _wout("}\n");
}

var Block = function (statements) {
  this.statements = statements
}
inherits(Block, Node)
Block.prototype.print = function() {
  out.write("{\n")
  _ind += INDENT
  this.statements.forEach(function (stmt) {
    stmt.print()
    out.write("\n")
  })
  _ind -= INDENT
  _w('}')
  // out.write(repeat(' ', _ind - INDENT) + '}')
}

module.exports = {
  Node: Node,
  Let: Let,
  Var: Var,
  Path: Path,
  Root: Root,
  Assignment: Assignment,
  Expression: Expression,
  Binary: Binary,
  Literal: Literal,
  Group: Group,
  Function: Function,
  Block: Block,
  If: If,
  While: While,
  For: For,
  Chain: Chain,
  Return: Return,
  Call: Call
}

<commit_msg>Indentation bugfix<commit_after>
var inherits = require('util').inherits,
    inspect  = require('util').inspect,
    out      = process.stdout

// http://stackoverflow.com/a/5450113
var repeat = function (pattern, count) {
  if (count < 1) return '';
  var result = ''
  while (count > 1) {
    if (count & 1) result += pattern;
    count >>= 1, pattern += pattern
  }
  return result + pattern
}

// TODO: Refactor all this crazy indentation stuff!
var INDENT = 2

var _ind = 0,
    _i   = function () { return repeat(' ', _ind) },
    _w   = function (s) { out.write(_i() + s) },
    _win = function (s) {
      // Indent and write
      _w(s); _ind += INDENT
    },
    _wout = function (s) { _ind -= INDENT; _w(s) }

// Nodes ----------------------------------------------------------------------

var Node = function () {}
Node.prototype.print = function () { out.write(inspect(this)) }

var Let = function Let(name, typepath) {
  this.name = name.trim()
  this.typepath = typepath
}
inherits(Let, Node)
Let.prototype.print    = function () { _w(this.toString()+"\n") }
Let.prototype.toString = function () { return this.name }

// Quick and dirty clone of Let
var Var = Let.bind({})
inherits(Var, Node)
Var.prototype.print    = Let.prototype.print
Var.prototype.toString = Let.prototype.toString

var Expression = function () {}
inherits(Expression, Node)

var Group = function Group(expr) {
  this.expr = expr
}
inherits(Group, Expression)
Group.prototype.toString = function () { return '('+this.expr.toString()+')' }

var Binary = function (lexpr, op, rexpr) {
  this.lexpr = lexpr
  this.op    = op
  this.rexpr = rexpr
}
inherits(Binary, Expression)
Binary.prototype.print = function () { out.write(this.toString()) }
Binary.prototype.toString = function () {
  return this.lexpr.toString()+' '+this.op+' '+this.rexpr.toString()
}

var Literal = function Literal(value) {
  this.value = value
}
inherits(Literal, Node)
Literal.prototype.print    = function () { out.write(this.toString()) }
Literal.prototype.toString = function () { return this.value.toString() }

var Assignment = function (type, lvalue, rvalue) {
  this.type   = type
  this.lvalue = lvalue
  this.rvalue = rvalue
}
inherits(Assignment, Node)
Assignment.prototype.print = function () {
  var type = (this.type != 'path') ? (this.type+' ') : ''
  out.write(type + this.lvalue.toString()+' = ')
  if (this.rvalue) {
    // _ind += INDENT
    this.rvalue.print()
    // _ind -= INDENT
  }
}

var Path = function (name) { this.name = name }
inherits(Path, Node)
Path.prototype.toString = function () { return this.name }

var Function = function (args, block) {
  this.args  = args
  this.block = block
}
inherits(Function, Node)
Function.prototype.print = function () {
  var args = this.args.map(function (arg) {
    var ret = arg.name
    if (arg.type) {
      ret += ': '+arg.type
    }
    return ret
  }).join(', ')
  out.write('func ('+args+') ')
  this.block.print()
}

var Call = function (args) {
  this.args = args
}
inherits(Call, Node)
Call.prototype.toString = function () {
  return '('+this.args.map(function (arg) { return arg.toString() }).join(', ')+')'
}

var If = function (cond, block) {
  this.cond  = cond
  this.block = block
}
inherits(If, Node)
If.prototype.print = function () {
  var cond = this.cond.toString()
  out.write("if "+cond+" ")
  this.block.print()
}

var While = function (expr, block) {
  this.expr  = expr // Loop expression
  this.block = block
}
inherits(While, Node)
While.prototype.print = function () {
  out.write("while "+this.expr.toString()+" ")
  this.block.print()
}

var For = function (init, cond, after, block) {
  this.init  = init // Initialization
  this.cond  = cond // Condition
  this.after = after // Afterthought
  this.block = block
}
inherits(For, Node)
For.prototype.print = function () {
  out.write("for ")
  // Don't indent while we're writing out these statements
  var i = _ind
  _ind = 0;
  this.init.print();  out.write('; ')
  this.cond.print();  out.write('; ')
  this.after.print(); out.write(' ')
  // Restore indent and print the block
  _ind = i;
  this.block.print()
}

var Chain = function (name, tail) {
  this.name = name
  this.tail = tail
}
inherits(Chain, Node)
Chain.prototype.toString = function () {
  var base = this.name
  this.tail.forEach(function (expr) {
    base += expr.toString()
  })
  return base
}
Chain.prototype.print = function () { out.write(this.toString()) }

var Return = function (expr) {
  this.expr = expr
}
inherits(Return, Node)
Return.prototype.print    = function () { out.write(this.toString()) }
Return.prototype.toString = function () { return 'return '+this.expr.toString() }

var Root = function (statements) {
  this.statements = statements
}
inherits(Root, Node)
Root.prototype.print = function() {
  _win("root {\n")
  this.statements.forEach(function (stmt) {
    _w('')
    stmt.print()
    out.write("\n")
  })
  _wout("}\n");
}

var Block = function (statements) {
  this.statements = statements
}
inherits(Block, Node)
Block.prototype.print = function() {
  out.write("{\n")
  _ind += INDENT
  this.statements.forEach(function (stmt) {
    _w('')
    stmt.print()
    out.write("\n")
  })
  _ind -= INDENT
  _w('}')
  // out.write(repeat(' ', _ind - INDENT) + '}')
}

module.exports = {
  Node: Node,
  Let: Let,
  Var: Var,
  Path: Path,
  Root: Root,
  Assignment: Assignment,
  Expression: Expression,
  Binary: Binary,
  Literal: Literal,
  Group: Group,
  Function: Function,
  Block: Block,
  If: If,
  While: While,
  For: For,
  Chain: Chain,
  Return: Return,
  Call: Call
}

<|endoftext|>


<commit_before>var Q = require('q'),
    cp = require('child_process');

exports.main = function () {

    var myPath = require('./path');
    require('coa').Cmd()
        .name(myPath.basename(process.argv[1]))
        .title('Инструменты работы с файлами, написанными по БЭМ-методу.')
        .helpful()
        .opt()
            .name('version').title('Версия')
            .short('v').long('version')
            .flag()
            .only()
            .act(function() {
                return JSON.parse(require('fs').readFileSync(
                    myPath.join(__dirname, '..', 'package.json')))
                        .version;
            })
            .end()
        .cmd().name('decl').apply(require('./commands/decl')).end()
        .cmd().name('build').apply(require('./commands/build')).end()
        .cmd().name('create').apply(require('./commands/create')).end()
        .completable()
        .act(function() {
            var defer = Q.defer(),
                readline = require('readline'),
                rl = readline.createInterface(process.stdin, process.stdout),
                prefix = '> ';
            rl.setPrompt(prefix, prefix.length);

            rl.on('line', function(line) {
                line = line.trim();
                if (!line) {
                    rl.prompt();
                    return;
                }
                var child = cp.spawn(process.argv[0],
                    process.argv.slice(1, 2).concat(line.split(' ')),
                    { cwd: process.cwd(), customFds: [-1, 1, 2] });
                child.on('exit', function (code) {
                    rl.prompt();
                });
            })
            .on('close', function() {
                console.log('');
                process.stdin.destroy();
                defer.resolve();
            });

            console.log("Type '--help' for help, press ctrl+d or ctrl+c to exit");
            rl.prompt();

            return defer.promise;
        })
        .run();

};
<commit_msg>Prettify of lib/bem.js<commit_after>exports.main = function () {

    var Q = require('q'),
        CP = require('child_process'),
        PATH = require('./path');

    require('coa').Cmd()
        .name(PATH.basename(process.argv[1]))
        .title('Инструменты работы с файлами, написанными по БЭМ-методу.')
        .helpful()
        .opt()
            .name('version').title('Версия')
            .short('v').long('version')
            .flag()
            .only()
            .act(function() {
                return JSON.parse(require('fs').readFileSync(
                    PATH.join(__dirname, '..', 'package.json')))
                        .version;
            })
            .end()
        .cmd().name('decl').apply(require('./commands/decl')).end()
        .cmd().name('build').apply(require('./commands/build')).end()
        .cmd().name('create').apply(require('./commands/create')).end()
        .completable()
        .act(function() {
            var defer = Q.defer(),
                readline = require('readline'),
                rl = readline.createInterface(process.stdin, process.stdout),
                prefix = '> ';
            rl.setPrompt(prefix, prefix.length);

            rl.on('line', function(line) {
                line = line.trim();
                if (!line) {
                    rl.prompt();
                    return;
                }
                var child = CP.spawn(process.argv[0],
                    process.argv.slice(1, 2).concat(line.split(' ')),
                    { cwd: process.cwd(), customFds: [-1, 1, 2] });
                child.on('exit', function (code) {
                    rl.prompt();
                });
            })
            .on('close', function() {
                console.log('');
                process.stdin.destroy();
                defer.resolve();
            });

            console.log("Type '--help' for help, press ctrl+d or ctrl+c to exit");
            rl.prompt();

            return defer.promise;
        })
        .run();

};
<|endoftext|>


<commit_before>'use strict';

var SlackClient = require('slack-client'),
  introject = require('introject');

var constants = require('./constants'),
  Response = require('./response').Response;

var Bot = function Bot(options) {
  this.client = new SlackClient(options.token);

  this.commands = {};
};

Bot.prototype.on = function on(type, cb) {
  // build a context. We will use this to inject dependencies.
  // bootstrap context with non event specific resources. can be injected
  // into any event.
  var context = {
    client: this.client,
    channels: this.client.channels,
    dms: this.client.dms,
    groups: this.client.groups,
    users: this.client.users,
    bots: this.client.bots
  };
  var response;

  this.client.on(type, function() {
    // build an array out of the arguments to this callback
    var args = Array.apply(null, arguments);

    // match up the arguments to constants.eventArgs, and then add to context
    constants.eventArgs[type].forEach(function(argName) {
      var arg = args.shift();
      context[argName] = arg;
    });

    // do some sort of seminonunintelligent context inference here
    if (context.message) {
      context.channel = context.client.getChannelGroupOrDMByID(context.message.channel);
      context.user = context.client.getUserByID(context.message.user);

      // TODO: don't construct response inside this if-block.
      response = new Response(context.channel);
    }

    // now, add our own deps
    context.response = response;

    // add the context itself as a dependency!
    context.context = context;

    // finally, inject stuff from our context to the callback, and run it
    introject.injectDeps(cb, context)();

    // if the callback put data into the response, send it.
    // TODO: somehow try to fix this for async callbacks.
    context.response.data && context.response.end();
  });
};

Bot.prototype.onMessage = function onMessage(subtype, cb) {
  if (typeof subtype === 'function') {
    cb = subtype;
    subtype = null;
  };

  this.on('message', function(context, message) {
    if (message.subtype === subtype || !subtype) {
      introject.injectDeps(cb, context)();
    }
  });
};

Bot.prototype.command = function command(name, cb) {
  // construct a hashset of the command names.
  var names = Array.isArray(name) ? name : [name];
  var commands = this.commands;
  names.forEach(function(name) {
    commands[name] = cb;
  });

  this.onMessage(function(context, message) {
    if (message.text && message.text.startsWith('!')) {
      message.text = message.text.slice(1);
    }
    else {
      return;
    }

    var words = message.text.split(' ');
    message.argv = context.argv = words;
    commands[words[0]] && introject.injectDeps(commands[words[0]], context)();
  });
};

Bot.prototype.start = function start() {
  this.client.login();
};

module.exports = Bot;
<commit_msg>Add method to import bundled plugins<commit_after>'use strict';

var SlackClient = require('slack-client'),
  introject = require('introject');

var constants = require('./constants'),
  Response = require('./response').Response;

var Bot = function Bot(options) {
  this.client = new SlackClient(options.token);

  this.commands = {};
};

Bot.prototype.on = function on(type, cb) {
  // build a context. We will use this to inject dependencies.
  // bootstrap context with non event specific resources. can be injected
  // into any event.
  var context = {
    client: this.client,
    channels: this.client.channels,
    dms: this.client.dms,
    groups: this.client.groups,
    users: this.client.users,
    bots: this.client.bots
  };
  var response;

  this.client.on(type, function() {
    // build an array out of the arguments to this callback
    var args = Array.apply(null, arguments);

    // match up the arguments to constants.eventArgs, and then add to context
    constants.eventArgs[type].forEach(function(argName) {
      var arg = args.shift();
      context[argName] = arg;
    });

    // do some sort of seminonunintelligent context inference here
    if (context.message) {
      context.channel = context.client.getChannelGroupOrDMByID(context.message.channel);
      context.user = context.client.getUserByID(context.message.user);

      // TODO: don't construct response inside this if-block.
      response = new Response(context.channel);
    }

    // now, add our own deps
    context.response = response;

    // add the context itself as a dependency!
    context.context = context;

    // finally, inject stuff from our context to the callback, and run it
    introject.injectDeps(cb, context)();

    // if the callback put data into the response, send it.
    // TODO: somehow try to fix this for async callbacks.
    context.response.data && context.response.end();
  });
};

Bot.prototype.onMessage = function onMessage(subtype, cb) {
  if (typeof subtype === 'function') {
    cb = subtype;
    subtype = null;
  };

  this.on('message', function(context, message) {
    if (message.subtype === subtype || !subtype) {
      introject.injectDeps(cb, context)();
    }
  });
};

Bot.prototype.command = function command(name, cb) {
  // construct a hashset of the command names.
  var names = Array.isArray(name) ? name : [name];
  var commands = this.commands;
  names.forEach(function(name) {
    commands[name] = cb;
  });

  this.onMessage(function(context, message) {
    if (message.text && message.text.startsWith('!')) {
      message.text = message.text.slice(1);
    }
    else {
      return;
    }

    var words = message.text.split(' ');
    message.argv = context.argv = words;
    commands[words[0]] && introject.injectDeps(commands[words[0]], context)();
  });
};

Bot.prototype.start = function start() {
  this.client.login();
};

Bot.prototype.importBundle = function importBundle(bundle) {
  (typeof bundle === 'string') && (bundle = require(string));
  bundle(this);
};

module.exports = Bot;
<|endoftext|>


<commit_before>var _ = require('underscore');
var IRC = require('irc');
var slack = require('./slacker');

/**
 * IRC Bot for syncing messages from IRC to Slack
 * @param {object} config Bot configuration
 * - server: IRC server
 * - nick: Bot IRC nickname
 * - token: Slack token
 * - channels: List of IRC channels to watch
 * - users: Map of ~login: slack usernames
 */
var Bot = function (config) {
    var self = this;
    this.config = _.defaults(config, {
        silent: false,
        nick: 'slckbt',
        username: 'slckbt'
    });
    // default node-irc options
    // (@see https://github.com/martynsmith/node-irc/blob/0.3.x/lib/irc.js)
    this.irc = {
        userName: this.config.username,
        channels: Object.keys(this.config.channels),
        floodProtection: true
    };
    ['floodProtection', 'port', 'debug', 'showErrors', 'autoRejoin',
     'autoConnect', 'secure', 'selfSigned', 'certExpired',
     'floodProtection', 'floodProtectionDelay', 'sasl', 'stripColors',
     'channelPrefixes', 'messageSplit'].forEach(function (opt) {
        if (self.config[opt]) {
            self.irc[opt] = self.config[opt];
        }
    });
    this._usermap = {
        users: this.config.users || {},
        nicks: {}
    };
    this.client = new IRC.Client(this.config.server, this.config.nick, this.irc);
    this.slacker = new slack.Slacker({ token: this.config.token });
    this._trackUsers();
    this._handleErrors();
    return this;
};

/**
 * Whenever an error is provided catch is and let the channel know
 */
Bot.prototype._handleErrors = function () {
    var self = this;
    this.client.addListener('error', function (message) {
        var channel = message.args[1];
        var error_message = mapPronouns(message.args[2]);
        self.speak(channel, 'I don\'t feel so well because ' + error_message);
    });
};

/**
 * Find and track IRC users -> slack user mapping
 */
Bot.prototype._trackUsers = function () {
    var self = this;
    var myusername = '~' + self.config.username;
    // On entrance, track all existing names
    this.client.addListener('names', function (channel, nicks) {
        Object.keys(nicks).forEach(function (nick) {
            self.client.whois(nick, function (whois) {
                if (whois.user === myusername) {
                    return;
                }
                self._usermap.nicks[nick] = self._usermap.users[whois.user];
            });
        });
        self.speak(channel, 'I\'m all over you slackers');
    });
    // New user has joined, match him up
    this.client.addListener('join', function (channel, nick, whois) {
        if (whois.user == myusername) {
            return;
        }
        else {
            self._usermap.nicks[nick] = self._usermap.users[whois.user];
            self.giveOps(channel, nick);
            self.speak(channel, 'i\'m watching you slacker @' +
                       self._usermap.nicks[nick]);
        }
    });
    // Existing user has changed nickname
    this.client.addListener('nick', function (old_nick, new_nick, channels) {
        if (new_nick === self.config.nick) {
            return;
        }
        self._usermap.nicks[new_nick] = self._usermap.nicks[old_nick];
        delete self._usermap.nicks[old_nick];
        channels.forEach(function (channel) {
            self.speak(channel, 'don\'t think you can hide slacker @' +
                       self._usermap.nicks[new_nick]);
        });
    });
};

/**
 * Attempt to give a user op controls
 * @param {string} channel IRC channel name
 * @param {string} nick User to provide op status to
 */
Bot.prototype.giveOps = function (channel, nick) {
    this.client.send('MODE', channel, '+o', nick);
};

/**
 * Handle post and pass it to slack
 */
Bot.prototype.listen = function () {
    var self = this;
    // Handle public user post
    this.client.addListener('message', function (from, to, message) {
        self.slacker.send('chat.postMessage', {
            channel: '#irc',
            text: self.prepareMessage(message, self._usermap.nicks),
            username: self._usermap.nicks[from] || from,
            parse: 'full',
            link_names: 1,
            unfurl_links: 1
        });
    });
};

/**
 * Push a message to a channel
 * @param {string} channel IRC channel name
 * @param {string} message Message to push to channel
 */
Bot.prototype.speak = function (channel, message) {
    if (!this.config.silent) {
        this.client.say(channel, message);
    }
};

/**
 * Map users with whois to get ~loginname for stability
 * @param {string} message Message to replace IRC user with slack @user
 * @param {array} users User mapping
 * @return {string} Message with slack @users
 */
Bot.prototype.prepareMessage = function (message, users) {
    Object.keys(users).forEach(function (name) {
        if (message.indexOf(name) >= 0) {
            if (users[name] !== undefined) {
                message = message.replace(new RegExp(name, 'g'), '@' + users[name]);
            }
        }
    });
    return message;
};

/**
 * Try and map error commands (in third person) to first person
 * so the bot is more personal.
 */
var mapPronouns = function (message) {
    var map = {
        'you': 'i',
        'you\'re': 'i\'m'
    };
    return message.split(' ').map(function (word) {
        return map[word.toLowerCase()] ? map[word.toLowerCase()] : word;
    }).join(' ');
};

exports = module.exports.Bot = Bot;
<commit_msg>If no ~ is provided in your usermap, then add it in #7<commit_after>var _ = require('underscore');
var IRC = require('irc');
var slack = require('./slacker');

/**
 * IRC Bot for syncing messages from IRC to Slack
 * @param {object} config Bot configuration
 * - server: IRC server
 * - nick: Bot IRC nickname
 * - token: Slack token
 * - channels: List of IRC channels to watch
 * - users: Map of ~login: slack usernames
 */
var Bot = function (config) {
    var self = this;
    this.config = _.defaults(config, {
        silent: false,
        nick: 'slckbt',
        username: 'slckbt'
    });
    // default node-irc options
    // (@see https://github.com/martynsmith/node-irc/blob/0.3.x/lib/irc.js)
    this.irc = {
        userName: this.config.username,
        channels: Object.keys(this.config.channels),
        floodProtection: true
    };
    ['floodProtection', 'port', 'debug', 'showErrors', 'autoRejoin',
     'autoConnect', 'secure', 'selfSigned', 'certExpired',
     'floodProtection', 'floodProtectionDelay', 'sasl', 'stripColors',
     'channelPrefixes', 'messageSplit'].forEach(function (opt) {
        if (self.config[opt]) {
            self.irc[opt] = self.config[opt];
        }
    });
    // ensure tilde is present if not provided by the user
    Object.keys(this.config.users).forEach(function (username) {
        if (username[0] !== "~") {
            self.config.users["~" + username] = self.config.users[username];
            delete self.config.users[username];
        }
    });
    this._usermap = {
        users: this.config.users || {},
        nicks: {}
    };
    this.client = new IRC.Client(this.config.server, this.config.nick, this.irc);
    this.slacker = new slack.Slacker({ token: this.config.token });
    this._trackUsers();
    this._handleErrors();
    return this;
};

/**
 * Whenever an error is provided catch is and let the channel know
 */
Bot.prototype._handleErrors = function () {
    var self = this;
    this.client.addListener('error', function (message) {
        var channel = message.args[1];
        var error_message = mapPronouns(message.args[2]);
        self.speak(channel, 'I don\'t feel so well because ' + error_message);
    });
};

/**
 * Find and track IRC users -> slack user mapping
 */
Bot.prototype._trackUsers = function () {
    var self = this;
    var myusername = '~' + self.config.username;
    // On entrance, track all existing names
    this.client.addListener('names', function (channel, nicks) {
        Object.keys(nicks).forEach(function (nick) {
            self.client.whois(nick, function (whois) {
                if (whois.user === myusername) {
                    return;
                }
                self._usermap.nicks[nick] = self._usermap.users[whois.user];
            });
        });
        self.speak(channel, 'I\'m all over you slackers');
    });
    // New user has joined, match him up
    this.client.addListener('join', function (channel, nick, whois) {
        if (whois.user == myusername) {
            return;
        }
        else {
            self._usermap.nicks[nick] = self._usermap.users[whois.user];
            self.giveOps(channel, nick);
            self.speak(channel, 'i\'m watching you slacker @' +
                       self._usermap.nicks[nick]);
        }
    });
    // Existing user has changed nickname
    this.client.addListener('nick', function (old_nick, new_nick, channels) {
        if (new_nick === self.config.nick) {
            return;
        }
        self._usermap.nicks[new_nick] = self._usermap.nicks[old_nick];
        delete self._usermap.nicks[old_nick];
        channels.forEach(function (channel) {
            self.speak(channel, 'don\'t think you can hide slacker @' +
                       self._usermap.nicks[new_nick]);
        });
    });
};

/**
 * Attempt to give a user op controls
 * @param {string} channel IRC channel name
 * @param {string} nick User to provide op status to
 */
Bot.prototype.giveOps = function (channel, nick) {
    this.client.send('MODE', channel, '+o', nick);
};

/**
 * Handle post and pass it to slack
 */
Bot.prototype.listen = function () {
    var self = this;
    // Handle public user post
    this.client.addListener('message', function (from, to, message) {
        self.slacker.send('chat.postMessage', {
            channel: '#irc',
            text: self.prepareMessage(message, self._usermap.nicks),
            username: self._usermap.nicks[from] || from,
            parse: 'full',
            link_names: 1,
            unfurl_links: 1
        });
    });
};

/**
 * Push a message to a channel
 * @param {string} channel IRC channel name
 * @param {string} message Message to push to channel
 */
Bot.prototype.speak = function (channel, message) {
    if (!this.config.silent) {
        this.client.say(channel, message);
    }
};

/**
 * Map users with whois to get ~loginname for stability
 * @param {string} message Message to replace IRC user with slack @user
 * @param {array} users User mapping
 * @return {string} Message with slack @users
 */
Bot.prototype.prepareMessage = function (message, users) {
    Object.keys(users).forEach(function (name) {
        if (message.indexOf(name) >= 0) {
            if (users[name] !== undefined) {
                message = message.replace(new RegExp(name, 'g'), '@' + users[name]);
            }
        }
    });
    return message;
};

/**
 * Try and map error commands (in third person) to first person
 * so the bot is more personal.
 */
var mapPronouns = function (message) {
    var map = {
        'you': 'i',
        'you\'re': 'i\'m'
    };
    return message.split(' ').map(function (word) {
        return map[word.toLowerCase()] ? map[word.toLowerCase()] : word;
    }).join(' ');
};

exports = module.exports.Bot = Bot;
<|endoftext|>