<commit_before>goog.provide('lime.scheduleManager');

goog.require('goog.array');
goog.require('goog.userAgent');
goog.require('lime');

/**
 * Unified timer provider class
 * Don't create instances of this class. Used the shared instance.
 * @this {lime.scheduleManager}
 * @constructor
 */
lime.scheduleManager = new (function() {

    /**
     * Array of registered functions
     * @type {Array.<lime.scheduleManager.Task>}
     * @private
     */
    this.taskStack_ = [];

    /**
     * ScheduleManager is active
     * @type {boolean}
     * @private
     */
    this.active_ = false;

    /**
     * Internal setInterval id
     * @type {number}
     * @private
     */
    this.intervalID_ = 0;

    /**
     * Maximum update rate in ms.
     * @type {number}
     * @private
     */
    this.displayRate_ = 1000 / 30;

    /**
     * Timer last fire timestamp
     * @type {number}
     * @private
     */
    this.lastRunTime_ = 0;

})();

/**
 * Scheduled task
 * @param {number} maxdelta Timer wait value after iteration.
 * @param {number=} opt_limit Number of calls.
 * @constructor
 */
lime.scheduleManager.Task = function(maxdelta, opt_limit) {
    this.delta = this.maxdelta = maxdelta;
    this.limit = goog.isDef(opt_limit) ? opt_limit : -1;
    this.functionStack_ = [];
};

/**
 * Handle iteration
 * @param {number} dt Delta time since last iteration.
 * @private
 */
lime.scheduleManager.Task.prototype.step_ = function(dt) {
    if (!this.functionStack_.length) return;
    if (this.delta > dt) {
        this.delta -= dt;
    }
    else {
        var delta = this.maxdelta + dt - this.delta;
        this.delta = this.maxdelta - (dt - this.delta);
        if (this.delta < 0) this.delta = 0;
        var f;
        var i = this.functionStack_.length;
        while (--i >= 0) {
            f = this.functionStack_[i];
            if (f && f[0] && goog.isFunction(f[1]))
            (f[1]).call(f[2], delta);
        }
        if (this.limit != -1) {
            this.limit--;
            if (this.limit == 0) {
                lime.scheduleManager.unschedule(f[1], f[2]);
            }
        }
    }
};

lime.scheduleManager.taskStack_.push(new lime.scheduleManager.Task(0));

(function() {
    var vendors = ['webkit', 'moz'];
    for(var x = 0; x < vendors.length && !goog.global.requestAnimationFrame; ++x) {
        goog.global.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        goog.global.cancelAnimationFrame =
          goog.global[vendors[x]+'CancelAnimationFrame'] || goog.global[vendors[x]+'CancelRequestAnimationFrame'];
    }
}());

/**
 * Whether to use requestAnimationFrame instead of timer events
 * Exposed here so it could be disabled if needed.
 * @type {boolean}
 */
lime.scheduleManager.USE_ANIMATION_FRAME = !!goog.global.requestAnimationFrame;

/**
 * Returns maximum fire rate in ms. If you need FPS then use 1000/x
 * @this {lime.scheduleManager}
 * @return {number} Display rate.
 */
lime.scheduleManager.getDisplayRate = function() {
    //todo: bad name
    return this.displayRate_;
};

/**
 * Sets maximum fire rate for the scheduler in ms.
 * If you have FPS then send 1000/x
 * Note that if animation frame methods are used browser chooses
 * max display rate and this value has no effect.
 * @this {lime.scheduleManager}
 * @param {number} value New display rate.
 */
lime.scheduleManager.setDisplayRate = function(value) {
     this.displayRate_ = value;
     if (this.active_) {
         lime.scheduleManager.disable_();
         lime.scheduleManager.activate_();
     }
};

/**
 * Schedule a function. Passed function will be called on every frame
 * with delta time from last run time
 * @this {lime.scheduleManager}
 * @param {function(number)} f Function to be called.
 * @param {Object} context The context used when calling function.
 * @param {lime.scheduleManager.Task=} opt_task Task object.
 */
lime.scheduleManager.schedule = function(f, context, opt_task) {
    var task = goog.isDef(opt_task) ? opt_task : this.taskStack_[0];
    goog.array.insert(task.functionStack_, [1, f, context]);
    goog.array.insert(this.taskStack_, task);
    if (!this.active_) {
        lime.scheduleManager.activate_();
    }
};

/**
 * Unschedule a function. For functions that have be previously scheduled
 * @this {lime.scheduleManager}
 * @param {function(number)} f Function to be unscheduled.
 * @param {Object} context Context used when scheduling.
 */
lime.scheduleManager.unschedule = function(f, context) {
    var j = this.taskStack_.length;
    while (--j >= 0) {
        var task = this.taskStack_[j],
            functionStack_ = task.functionStack_,
            fi, i = functionStack_.length;
        while (--i >= 0) {
            fi = functionStack_[i];
            if (fi[1] == f && fi[2] == context) {
                goog.array.remove(functionStack_, fi);

            }
        }
        if (functionStack_.length == 0 && j != 0) {
           goog.array.remove(this.taskStack_, task);
        }
    }
    // if no more functions: stop timers
    if (this.taskStack_.length == 1 &&
            this.taskStack_[0].functionStack_.length == 0) {
        lime.scheduleManager.disable_();
    }
};

/**
 * Start the internal timer functions
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.activate_ = function() {
    if (this.active_) return;

    this.lastRunTime_ = this.now();

    if(lime.scheduleManager.USE_ANIMATION_FRAME && goog.global.requestAnimationFrame) {
        // old mozilla
        if(goog.global['mozRequestAnimationFrame'] && goog.userAgent.VERSION < 11) {
            goog.global['mozRequestAnimationFrame']();
            this.beforePaintHandlerBinded_ = goog.bind(lime.scheduleManager.beforePaintHandler_,this);
            goog.global.addEventListener('MozBeforePaint',this.beforePaintHandlerBinded_, false);
        }
        else {
            this.animationFrameHandlerBinded_ = goog.bind(lime.scheduleManager.animationFrameHandler_,this);
            goog.global.requestAnimationFrame(this.animationFrameHandlerBinded_);
        }
    }
    else {
        this.intervalID_ = setInterval(goog.bind(lime.scheduleManager.stepTimer_, this),
            lime.scheduleManager.getDisplayRate());
    }
    this.active_ = true;
};

(function() {

var performance = goog.global['performance']
var now = performance && (performance['now'] || performance['webkitNow'])

lime.scheduleManager.now = function() {
    return now ? now.call(performance) : goog.now();
};

})();

/**
 * Stop interval timer functions
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.disable_ = function() {
    if (!this.active_) return;

    if(lime.scheduleManager.USE_ANIMATION_FRAME && goog.global.requestAnimationFrame) {
        // old mozilla
        if(goog.global['mozRequestAnimationFrame'] && goog.userAgent.VERSION < 11) {
            goog.global.removeEventListener('MozBeforePaint',this.beforePaintHandlerBinded_, false);
        }
        else {
            goog.global.cancelAnimationFrame(this.animationFrameHandlerBinded_);
        }
    }
    else {
        clearInterval(this.intervalID_);
    }
    this.active_ = false;
};

/**
 * Webkit implemtation of requestAnimationFrame handler.
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.animationFrameHandler_ = function(){
    time = this.now()
    var delta = time - this.lastRunTime_;
    if (delta < 0) { // i0S6 reports relative to the device restart time. So first is negative.
        delta = 1;
    }
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = time;
    goog.global.requestAnimationFrame(this.animationFrameHandlerBinded_);
}

/**
 * Mozilla < 11 implementation of requestAnimationFrame handler.
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.beforePaintHandler_ = function(event){
    var delta = event.timeStamp - this.lastRunTime_;
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = event.timeStamp;
    goog.global['mozRequestAnimationFrame']();
}

/**
 * Timer events step function that delegates to other objects waiting
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.stepTimer_ = function() {
    var t;
    var curTime = this.now();
    var delta = curTime - this.lastRunTime_;
    if (delta < 0) delta = 1;
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = curTime;
};

/**
 * Call all scheduled tasks
 * @this {lime.scheduleManager}
 * @param {number} delta Milliseconds since last run.
 * @private
 */
lime.scheduleManager.dispatch_ = function(delta){

    var stack = this.taskStack_.slice()
    var i = stack.length;
    while (--i >= 0) stack[i].step_(delta);
    //hack to deal with FF4 CSS transformation issue https://bugzilla.mozilla.org/show_bug.cgi?id=637597
    if(lime.transformSet_ == 1 && (/Firefox\/18./).test(goog.userAgent.getUserAgentString()) &&
       !lime.FF4_USE_HW_ACCELERATION){
        if(lime.scheduleManager.odd_){
            document.body.style['MozTransform'] = '';
            lime.scheduleManager.odd_=0;
        }
        else {
            document.body.style['MozTransform'] = 'scale(1,1)';
            lime.scheduleManager.odd_=1;
        }
        lime.transformSet_=0;
    }
};

/**
 * Change director's activity. Used for pausing updates when director is paused
 * @this {lime.scheduleManager}
 * @param {lime.Director} director Director.
 * @param {boolean} value Active or inactive?
 */
lime.scheduleManager.changeDirectorActivity = function(director, value) {
    var t, context, f, d, i,
    j = this.taskStack_.length;
    while (--j >= 0) {

        t = this.taskStack_[j];
        i = t.functionStack_.length;
        while (--i >= 0) {
            f = t.functionStack_[i];
            context = f[2];
            if (goog.isFunction(context.getDirector)) {
                d = context.getDirector();
                if (d == director) {
                    f[0] = value;
                }
            }
        }
    }
};

/**
 * Set up function to be called once after a delay
 * @param {function(number)} f Function to be called.
 * @param {Object} context Context used when calling object.
 * @param {number} delay Delay before calling.
 */
lime.scheduleManager.callAfter = function(f, context, delay) {
    lime.scheduleManager.scheduleWithDelay(f, context, delay, 1);
};

/**
 * Set up function to be called repeatedly after a delay
 * @param {function(number)} f Function to be called.
 * @param {Object} context Context used when calling object.
 * @param {number} delay Delay before calling.
 * @param {number=} opt_limit Number of times to call.
 * @this {lime.scheduleManager}
 */
lime.scheduleManager.scheduleWithDelay = function(f, context,
        delay, opt_limit) {
    var task = new lime.scheduleManager.Task(delay, opt_limit);
    lime.scheduleManager.schedule(f, context, task);
};
<commit_msg>Use struct callback instead of array for readability<commit_after>goog.provide('lime.scheduleManager');

goog.require('goog.array');
goog.require('goog.userAgent');
goog.require('lime');

/**
 * Unified timer provider class
 * Don't create instances of this class. Used the shared instance.
 * @this {lime.scheduleManager}
 * @constructor
 */
lime.scheduleManager = new (function() {

    /**
     * Array of registered functions
     * @type {Array.<lime.scheduleManager.Task>}
     * @private
     */
    this.taskStack_ = [];

    /**
     * ScheduleManager is active
     * @type {boolean}
     * @private
     */
    this.active_ = false;

    /**
     * Internal setInterval id
     * @type {number}
     * @private
     */
    this.intervalID_ = 0;

    /**
     * Maximum update rate in ms.
     * @type {number}
     * @private
     */
    this.displayRate_ = 1000 / 30;

    /**
     * Timer last fire timestamp
     * @type {number}
     * @private
     */
    this.lastRunTime_ = 0;

})();

lime.scheduleManager.Callback = function (f, ctx) {
    this.f = f;
    this.ctx = ctx;
    this.paused = false;
    this.offset = 0;
    this.pauseTime = 0;
}

/**
 * Scheduled task
 * @param {number} maxdelta Timer wait value after iteration.
 * @param {number=} opt_limit Number of calls.
 * @constructor
 */
lime.scheduleManager.Task = function(maxdelta, opt_limit) {
    this.delta = this.maxdelta = maxdelta;
    this.limit = goog.isDef(opt_limit) ? opt_limit : -1;
    this.functionStack_ = [];
};

/**
 * Handle iteration
 * @param {number} dt Delta time since last iteration.
 * @private
 */
lime.scheduleManager.Task.prototype.step_ = function(dt) {
    if (!this.functionStack_.length) return;
    if (this.delta > dt) {
        this.delta -= dt;
    }
    else {
        var delta = this.maxdelta + dt - this.delta;
        this.delta = this.maxdelta - (dt - this.delta);
        if (this.delta < 0) this.delta = 0;
        var f;
        var i = this.functionStack_.length;
        while (--i >= 0) {
            f = this.functionStack_[i];
            if (f && !f.paused && goog.isFunction(f.f))
            (f.f).call(f.ctx, delta);
        }
        if (this.limit != -1) {
            this.limit--;
            if (this.limit == 0) {
                lime.scheduleManager.unschedule(f.f, f.ctx);
            }
        }
    }
};

lime.scheduleManager.taskStack_.push(new lime.scheduleManager.Task(0));

(function() {
    var vendors = ['webkit', 'moz'];
    for(var x = 0; x < vendors.length && !goog.global.requestAnimationFrame; ++x) {
        goog.global.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
        goog.global.cancelAnimationFrame =
          goog.global[vendors[x]+'CancelAnimationFrame'] || goog.global[vendors[x]+'CancelRequestAnimationFrame'];
    }
}());

/**
 * Whether to use requestAnimationFrame instead of timer events
 * Exposed here so it could be disabled if needed.
 * @type {boolean}
 */
lime.scheduleManager.USE_ANIMATION_FRAME = !!goog.global.requestAnimationFrame;

/**
 * Returns maximum fire rate in ms. If you need FPS then use 1000/x
 * @this {lime.scheduleManager}
 * @return {number} Display rate.
 */
lime.scheduleManager.getDisplayRate = function() {
    //todo: bad name
    return this.displayRate_;
};

/**
 * Sets maximum fire rate for the scheduler in ms.
 * If you have FPS then send 1000/x
 * Note that if animation frame methods are used browser chooses
 * max display rate and this value has no effect.
 * @this {lime.scheduleManager}
 * @param {number} value New display rate.
 */
lime.scheduleManager.setDisplayRate = function(value) {
     this.displayRate_ = value;
     if (this.active_) {
         lime.scheduleManager.disable_();
         lime.scheduleManager.activate_();
     }
};

/**
 * Schedule a function. Passed function will be called on every frame
 * with delta time from last run time
 * @this {lime.scheduleManager}
 * @param {function(number)} f Function to be called.
 * @param {Object} context The context used when calling function.
 * @param {lime.scheduleManager.Task=} opt_task Task object.
 */
lime.scheduleManager.schedule = function(f, context, opt_task) {
    var task = goog.isDef(opt_task) ? opt_task : this.taskStack_[0];
    goog.array.insert(task.functionStack_, new this.Callback(f, context));
    goog.array.insert(this.taskStack_, task);
    if (!this.active_) {
        lime.scheduleManager.activate_();
    }
};

/**
 * Unschedule a function. For functions that have be previously scheduled
 * @this {lime.scheduleManager}
 * @param {function(number)} f Function to be unscheduled.
 * @param {Object} context Context used when scheduling.
 */
lime.scheduleManager.unschedule = function(f, context) {
    var j = this.taskStack_.length;
    while (--j >= 0) {
        var task = this.taskStack_[j],
            functionStack_ = task.functionStack_,
            fi, i = functionStack_.length;
        while (--i >= 0) {
            fi = functionStack_[i];
            if (fi.f == f && fi.ctx == context) {
                goog.array.remove(functionStack_, fi);
            }
        }
        if (functionStack_.length == 0 && j != 0) {
           goog.array.remove(this.taskStack_, task);
        }
    }
    // if no more functions: stop timers
    if (this.taskStack_.length == 1 &&
            this.taskStack_[0].functionStack_.length == 0) {
        lime.scheduleManager.disable_();
    }
};

/**
 * Start the internal timer functions
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.activate_ = function() {
    if (this.active_) return;

    this.lastRunTime_ = this.now();

    if(lime.scheduleManager.USE_ANIMATION_FRAME && goog.global.requestAnimationFrame) {
        // old mozilla
        if(goog.global['mozRequestAnimationFrame'] && goog.userAgent.VERSION < 11) {
            goog.global['mozRequestAnimationFrame']();
            this.beforePaintHandlerBinded_ = goog.bind(lime.scheduleManager.beforePaintHandler_,this);
            goog.global.addEventListener('MozBeforePaint',this.beforePaintHandlerBinded_, false);
        }
        else {
            this.animationFrameHandlerBinded_ = goog.bind(lime.scheduleManager.animationFrameHandler_,this);
            goog.global.requestAnimationFrame(this.animationFrameHandlerBinded_);
        }
    }
    else {
        this.intervalID_ = setInterval(goog.bind(lime.scheduleManager.stepTimer_, this),
            lime.scheduleManager.getDisplayRate());
    }
    this.active_ = true;
};

(function() {

var performance = goog.global['performance']
var now = performance && (performance['now'] || performance['webkitNow'])

lime.scheduleManager.now = function() {
    return now ? now.call(performance) : goog.now();
};

})();

/**
 * Stop interval timer functions
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.disable_ = function() {
    if (!this.active_) return;

    if(lime.scheduleManager.USE_ANIMATION_FRAME && goog.global.requestAnimationFrame) {
        // old mozilla
        if(goog.global['mozRequestAnimationFrame'] && goog.userAgent.VERSION < 11) {
            goog.global.removeEventListener('MozBeforePaint',this.beforePaintHandlerBinded_, false);
        }
        else {
            goog.global.cancelAnimationFrame(this.animationFrameHandlerBinded_);
        }
    }
    else {
        clearInterval(this.intervalID_);
    }
    this.active_ = false;
};

/**
 * Webkit implemtation of requestAnimationFrame handler.
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.animationFrameHandler_ = function(){
    time = this.now()
    var delta = time - this.lastRunTime_;
    if (delta < 0) { // i0S6 reports relative to the device restart time. So first is negative.
        delta = 1;
    }
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = time;
    goog.global.requestAnimationFrame(this.animationFrameHandlerBinded_);
}

/**
 * Mozilla < 11 implementation of requestAnimationFrame handler.
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.beforePaintHandler_ = function(event){
    var delta = event.timeStamp - this.lastRunTime_;
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = event.timeStamp;
    goog.global['mozRequestAnimationFrame']();
}

/**
 * Timer events step function that delegates to other objects waiting
 * @this {lime.scheduleManager}
 * @private
 */
lime.scheduleManager.stepTimer_ = function() {
    var t;
    var curTime = this.now();
    var delta = curTime - this.lastRunTime_;
    if (delta < 0) delta = 1;
    lime.scheduleManager.dispatch_(delta);
    this.lastRunTime_ = curTime;
};

/**
 * Call all scheduled tasks
 * @this {lime.scheduleManager}
 * @param {number} delta Milliseconds since last run.
 * @private
 */
lime.scheduleManager.dispatch_ = function(delta){

    var stack = this.taskStack_.slice()
    var i = stack.length;
    while (--i >= 0) stack[i].step_(delta);
    //hack to deal with FF4 CSS transformation issue https://bugzilla.mozilla.org/show_bug.cgi?id=637597
    if(lime.transformSet_ == 1 && (/Firefox\/18./).test(goog.userAgent.getUserAgentString()) &&
       !lime.FF4_USE_HW_ACCELERATION){
        if(lime.scheduleManager.odd_){
            document.body.style['MozTransform'] = '';
            lime.scheduleManager.odd_=0;
        }
        else {
            document.body.style['MozTransform'] = 'scale(1,1)';
            lime.scheduleManager.odd_=1;
        }
        lime.transformSet_=0;
    }
};

/**
 * Change director's activity. Used for pausing updates when director is paused
 * @this {lime.scheduleManager}
 * @param {lime.Director} director Director.
 * @param {boolean} value Active or inactive?
 */
lime.scheduleManager.changeDirectorActivity = function(director, value) {
    var t, context, f, d, i,
    j = this.taskStack_.length;
    while (--j >= 0) {

        t = this.taskStack_[j];
        i = t.functionStack_.length;
        while (--i >= 0) {
            f = t.functionStack_[i];
            context = f.ctx;
            if (goog.isFunction(context.getDirector)) {
                d = context.getDirector();
                if (d == director) {
                    f.paused = value ? true : false;
                }
            }
        }
    }
};

/**
 * Set up function to be called once after a delay
 * @param {function(number)} f Function to be called.
 * @param {Object} context Context used when calling object.
 * @param {number} delay Delay before calling.
 */
lime.scheduleManager.callAfter = function(f, context, delay) {
    lime.scheduleManager.scheduleWithDelay(f, context, delay, 1);
};

/**
 * Set up function to be called repeatedly after a delay
 * @param {function(number)} f Function to be called.
 * @param {Object} context Context used when calling object.
 * @param {number} delay Delay before calling.
 * @param {number=} opt_limit Number of times to call.
 * @this {lime.scheduleManager}
 */
lime.scheduleManager.scheduleWithDelay = function(f, context,
        delay, opt_limit) {
    var task = new lime.scheduleManager.Task(delay, opt_limit);
    lime.scheduleManager.schedule(f, context, task);
};
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var express   = require('express');
var path      = require('path');
var api       = require('./lib/api');
var app       = module.exports = express();

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.use(express.favicon());
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('change this value to something unique'));
app.use(express.cookieSession());
app.use(express.compress());
app.use(api);
app.use(express.static(path.join(__dirname, '../../dist')));
app.use(app.router);

if ('development' === app.get('env')) {
  app.use(express.errorHandler());
}
<commit_msg>Remove favicon middleware<commit_after>
/**
 * Module dependencies.
 */

var express   = require('express');
var path      = require('path');
var api       = require('./lib/api');
var app       = module.exports = express();

app.set('port', process.env.PORT || 3000);
app.set('views', __dirname + '/views');
app.use(express.logger('dev'));
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser('change this value to something unique'));
app.use(express.cookieSession());
app.use(express.compress());
app.use(api);
app.use(express.static(path.join(__dirname, '../../dist')));
app.use(app.router);

if ('development' === app.get('env')) {
  app.use(express.errorHandler());
}
<|endoftext|>


<commit_before>'use strict';

var packageJson = require('./package.json')

module.exports = function(grunt) {

  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-browserify');
  grunt.loadNpmTasks('grunt-sass');
  grunt.loadNpmTasks('grunt-env');
  grunt.loadNpmTasks('grunt-electron');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-clean');

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    env: {
      dev  : { 'NODE_ENV' : 'development' },
      dist : { 'NODE_ENV' : 'production' }
    },
    clean: {
      dist: ['dist/*'],
    },
    browserify: {
      options: {
        transform: ['reactify', 'envify']
      },
      dev: {
        options: {
          browserifyOptions: { debug : true },
          watch: 'watch',
          alias: ['react:']  // Make React available externally for dev tools
        },
        src: ['app/js/app.js'],
        dest: 'app/js/bundle.js'
      },
      dist: {
        src: '<%= browserify.dev.src %>',
        dest: 'app/js/bundle.js'
      }
    },
    sass: {
      dev: {
        options: { outputStyle: 'expanded' },
        files: {
          'app/css/app.css': 'app/scss/app.scss'
        }
      },
      dist: {
        options: { outputStyle: 'compressed' },
        files: {
          'app/css/app.css': 'app/scss/app.scss'
        }
      }
    },
    watch: {
      sass: {
        files: ['app/scss/**/*.scss'],
        tasks: ['sass:dev']
      }
    },
    electron: {
      osx: {
        options: {
          name            : 'Cumulus',
          dir             : '.',
          out             : 'dist',
          icon            : 'cumulus.icns',
          version         : '0.28.2',
          platform        : 'darwin',
          arch            : 'x64',
          prune           : true,
          // ignore          : 'node_modules/',
          'app-version'   : packageJson.version,
          'app-bundle-id' : 'com.gillesdemey.cumulus'
        }
      }
    }
  });

  // Default task(s).
  grunt.registerTask('default', ['env:dev' ,'browserify:dev', 'sass:dev', 'watch']);
  grunt.registerTask('build',   ['env:dist', 'clean:dist', 'browserify:dist', 'sass:dist', 'electron']);
};<commit_msg>Updated Electron version, fixes #8<commit_after>'use strict';

var packageJson = require('./package.json')

module.exports = function(grunt) {

  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-browserify');
  grunt.loadNpmTasks('grunt-sass');
  grunt.loadNpmTasks('grunt-env');
  grunt.loadNpmTasks('grunt-electron');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-clean');

  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    env: {
      dev  : { 'NODE_ENV' : 'development' },
      dist : { 'NODE_ENV' : 'production' }
    },
    clean: {
      dist: ['dist/*'],
    },
    browserify: {
      options: {
        transform: ['reactify', 'envify']
      },
      dev: {
        options: {
          browserifyOptions: { debug : true },
          watch: 'watch',
          alias: ['react:']  // Make React available externally for dev tools
        },
        src: ['app/js/app.js'],
        dest: 'app/js/bundle.js'
      },
      dist: {
        src: '<%= browserify.dev.src %>',
        dest: 'app/js/bundle.js'
      }
    },
    sass: {
      dev: {
        options: { outputStyle: 'expanded' },
        files: {
          'app/css/app.css': 'app/scss/app.scss'
        }
      },
      dist: {
        options: { outputStyle: 'compressed' },
        files: {
          'app/css/app.css': 'app/scss/app.scss'
        }
      }
    },
    watch: {
      sass: {
        files: ['app/scss/**/*.scss'],
        tasks: ['sass:dev']
      }
    },
    electron: {
      osx: {
        options: {
          name            : 'Cumulus',
          dir             : '.',
          out             : 'dist',
          icon            : 'cumulus.icns',
          version         : '0.30.2',
          platform        : 'darwin',
          arch            : 'x64',
          prune           : true,
          // ignore          : 'node_modules/',
          'app-version'   : packageJson.version,
          'app-bundle-id' : 'com.gillesdemey.cumulus'
        }
      }
    }
  });

  // Default task(s).
  grunt.registerTask('default', ['env:dev' ,'browserify:dev', 'sass:dev', 'watch']);
  grunt.registerTask('build',   ['env:dist', 'clean:dist', 'browserify:dist', 'sass:dist', 'electron']);
};<|endoftext|>


<commit_before>var json = '';
var selectedRecords = [];
var currentRecord = 0;

$(document).ready(function () {
  loadRecords();
});

$(document).on('click', '.record', function () {
  currentRecord = parseInt($(this).attr('id').replace('record', ''));

  $('#adminModal').modal('toggle');

  $("#firstname-label").val(json[currentRecord].firstName);
  $("#lastname-label").val(json[currentRecord].lastName);
  $("#email-label").val(json[currentRecord].email);
  $("#phone-label").val(json[currentRecord].phone);
  $("#suggestions-label").val(json[currentRecord].suggestions);
  $("#diet-label").val(json[currentRecord].dietary);
  $("#resume-frame").attr("src", json[currentRecord].resume);
});

$(document).on('click', '#resumeDownloadButton', function () {
  downloadURI(json[currentRecord].resume, json[currentRecord].firstName+"-"+json[currentRecord].lastName+"-Resume");
});

function downloadURI(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();
}

$(document).on('click', '.check-record', function (e) {
  currentRecord = parseInt($(this).attr('id').replace('checkbox', ''));

  e.stopPropagation();

  selectedRecords.push(json[currentRecord].email);

  $(document).on('click', '#delete-button', function () {
    $.ajax({
      type:   "POST",
      url:    "http://108.24.150.90/LehighHacks/register.php",
      data:   {
          remove:  selectedRecords;
      },
      success: function(data) {
        $("#record-table").empty();
        $('#loading').show();
        loadRecords();
        selectedRecords.length = 0;
      }
    });
  });
});

$(document).on('click', '#refresh-button', function () {
  $("#record-table").empty();
  $('#loading').show();
  loadRecords();
});

function loadRecords(){
  $.ajax({
    url:    "http://108.24.150.90/LehighHacks/registrant_aggregator.php",
    type:   "POST",
    data:   {
        data:  "data"
    },
    success: function(data) {
      $('#loading').hide();

      if(data.indexOf("Error") > -1){
        $('#record-wrapper').append('

'+data.replace('Error', '')+'
');
      }
      else{
        console.log("success");
        json = $.parseJSON(data);
        for(var i=0; i<json.length; i++){
          console.log(json[i]);
          $("#record-table").append('
'+'<input type="checkbox" class="check-record" id="checkbox'+i+'">	'+json[i].firstName+'	'+json[i].lastName+'	'+json[i].email+'	'+json[i].phone+'
');
        }
      }
    }
  });
}
<commit_msg>check boxes admin screen<commit_after>var json = '';
var selectedRecords = [];
var currentRecord = 0;

$(document).ready(function () {
  loadRecords();
});

$(document).on('click', '.record', function () {
  currentRecord = parseInt($(this).attr('id').replace('record', ''));

  $('#adminModal').modal('toggle');

  $("#firstname-label").val(json[currentRecord].firstName);
  $("#lastname-label").val(json[currentRecord].lastName);
  $("#email-label").val(json[currentRecord].email);
  $("#phone-label").val(json[currentRecord].phone);
  $("#suggestions-label").val(json[currentRecord].suggestions);
  $("#diet-label").val(json[currentRecord].dietary);
  $("#resume-frame").attr("src", json[currentRecord].resume);
});

$(document).on('click', '#resumeDownloadButton', function () {
  downloadURI(json[currentRecord].resume, json[currentRecord].firstName+"-"+json[currentRecord].lastName+"-Resume");
});

function downloadURI(uri, name) {
  var link = document.createElement("a");
  link.download = name;
  link.href = uri;
  link.click();
}

$(document).on('click', '.check-record', function (e) {
  currentRecord = parseInt($(this).attr('id').replace('checkbox', ''));

  e.stopPropagation();

  selectedRecords.push(json[currentRecord].email);

  $(document).on('click', '#delete-button', function () {
    $.ajax({
      type:   "POST",
      url:    "http://108.24.150.90/LehighHacks/register.php",
      data:   {
          remove:  selectedRecords
      },
      success: function(data) {
        $("#record-table").empty();
        $('#loading').show();
        loadRecords();
        selectedRecords.length = 0;
      }
    });
  });
});

$(document).on('click', '#refresh-button', function () {
  $("#record-table").empty();
  $('#loading').show();
  loadRecords();
});

function loadRecords(){
  $.ajax({
    url:    "http://108.24.150.90/LehighHacks/registrant_aggregator.php",
    type:   "POST",
    data:   {
        data:  "data"
    },
    success: function(data) {
      $('#loading').hide();

      if(data.indexOf("Error") > -1){
        $('#record-wrapper').append('

'+data.replace('Error', '')+'
');
      }
      else{
        console.log("success");
        json = $.parseJSON(data);
        for(var i=0; i<json.length; i++){
          console.log(json[i]);
          $("#record-table").append('
'+'<input type="checkbox" class="check-record" id="checkbox'+i+'">	'+json[i].firstName+'	'+json[i].lastName+'	'+json[i].email+'	'+json[i].phone+'
');
        }
      }
    }
  });
}
<|endoftext|>


<commit_before>output = function() {
  output({
    canvas: $.create(canvas.createCanvas())
  });
};
<commit_msg>cb vs output, maximum call stack<commit_after>output = function() {
  cb({
    canvas: $.create(canvas.createCanvas())
  });
  done();
};
<|endoftext|>


<commit_before>'use strict'

var mongoose = require('mongoose')
  , Schema   = mongoose.Schema;

var schema = new mongoose.Schema({
  _id        : { type: String, unique: true, required: true, index: true },
  venue_id   : { type: String, ref: 'FoursquareVenue', required: true },
  prefix     : { type: String, required: true },
  suffix     : { type: String, required: true },
  createdAt  : { type: Date, default: Date.now }

}, {
  _id: false,
  autoIndex: false,
  toJSON: {
    minimize: false,
    transform: function(doc, ret, options){
      delete ret._id;
      ret.id = doc.id;
    }
  }
});

schema.statics.newFromRef = function(ref){
  if (!ref || !ref.id || !ref.venueId) return null;
  var photo = new this({
    _id         : ref.id,
    venue_id   : ref.venueId,
    prefix     : ref.prefix,
    suffix     : ref.suffix,
    createdAt  : ref.createdAt
  });
  return photo;
};

module.exports = mongoose.model('FoursquarePhoto', schema);
<commit_msg>spacing<commit_after>'use strict'

var mongoose = require('mongoose')
  , Schema   = mongoose.Schema;

var schema = new mongoose.Schema({
  _id        : { type: String, unique: true, required: true, index: true },
  venue_id   : { type: String, ref: 'FoursquareVenue', required: true },
  prefix     : { type: String, required: true },
  suffix     : { type: String, required: true },
  createdAt  : { type: Date, default: Date.now }

}, {
  _id: false,
  autoIndex: false,
  toJSON: {
    minimize: false,
    transform: function(doc, ret, options){
      delete ret._id;
      ret.id = doc.id;
    }
  }
});

schema.statics.newFromRef = function(ref){
  if (!ref || !ref.id || !ref.venueId) return null;
  var photo = new this({
    _id        : ref.id,
    venue_id   : ref.venueId,
    prefix     : ref.prefix,
    suffix     : ref.suffix,
    createdAt  : ref.createdAt
  });
  return photo;
};

module.exports = mongoose.model('FoursquarePhoto', schema);
<|endoftext|>


<commit_before>define(function(require) {
  'use strict';

  var module = require('./module');

  module.config(configure);

  //---

  configure.$inject = ['$routeProvider'];

  function configure($routeProvider) {

    $routeProvider
      .when(
        '/about',
        {
          controller: 'AboutCtrl',
          controllerAs: 'vm',
          templateUrl: 'app/about/templates/page.html'
        }
      );

  }

});
<commit_msg>src/app/about code style update #32<commit_after>define(function(require) {
  'use strict';

  var module = require('./module');

  module.config(configure);

  //---

  configure.$inject = ['$routeProvider'];

  function configure($routeProvider) {

    $routeProvider
      .when(
        '/about',
        {
          templateUrl: 'app/about/templates/page.html',
          controller: 'AboutCtrl',
          controllerAs: 'vm'
        }
      );

  }

});
<|endoftext|>


<commit_before>var gamename = 'smurfs.zip';
var game_file = null;
var js_data = null;
var bios_filenames = 'coleco.zip'.split(' ');
var bios_files = {};
var requests = [];
var file_countdown = 1;
if (bios_filenames.length !== 0 && bios_filenames[0] !== '') {
  file_countdown += bios_filenames.length;
}
if (gamename !== '') {
  file_countdown++;
}

var newCanvas = document.createElement('canvas');
newCanvas.id = 'canvas';
newCanvas.width = 256;
newCanvas.height = 256;
var holder = document.getElementById('canvasholder');
holder.appendChild(newCanvas);

var draw_loading_status = function() {
  var font_height = 18;
  var line_height = (newCanvas.height - (font_height * 2)) / (requests.length);
  var context = newCanvas.getContext('2d');
  context.clearRect(0, 0, newCanvas.width, newCanvas.height);
  context.font = font_height + 'px sans-serif';
  context.fillStyle = 'Black';
  context.fillText('Loading...', 0, font_height);
  for(var i = 0; i < requests.length; i++) {
     var o = requests[i];
     var y = (line_height * i) + (font_height * 2);
     context.fillStyle = 'Red';
     context.fillRect(0, y, newCanvas.width, line_height);
     context.fillStyle = 'Green';
     context.fillRect(0, y, newCanvas.width * o.progress, line_height);
     context.fillStyle = 'Black';
     context.fillText(o.title + ' ' + Math.round(o.progress * 100) + '%', 0, y + (font_height / 2) + (line_height / 2));
}
}

var progress_fetch_file = function(e) {
  if(e.lengthComputable) {
    e.target.progress = e.loaded / e.total;
    draw_loading_status();
  }
}

var fetch_file = function(title, url, cb, rt, raw) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url, true);
  xhr.responseType = rt ? rt : "arraybuffer";
  xhr.onload = function(e) {
    xhr.progress = 1.0;
    draw_loading_status();
    var ints = raw ? xhr.response :  new Int8Array(xhr.response);
    cb(ints);
  };
  xhr.onprogress = progress_fetch_file;
  xhr.title = title;
  xhr.progress = 0;
  requests.push(xhr);
  xhr.send();
};

var Module = {
  'arguments': ["coleco","-verbose","-rompath",".","-cart",gamename,"-window","-resolution","256x192","-nokeepaspect"],
  print: (function() {
    var element = document.getElementById('output');
    return function(text) {
      text = text.replace(/&/g, "&");
      text = text.replace(/</g, "<");
      text = text.replace(/>/g, ">");
      text = text.replace('\n', '
', 'g');
      element.innerHTML += text + '
';
    };
  })(),
  canvas: document.getElementById('canvas'),
  noInitialRun: false,
  preInit: function() {
    // Load the downloaded binary files into the filesystem.
    for (var bios_fname in bios_files) {
      if (bios_files.hasOwnProperty(bios_fname)) {
        Module['FS_createDataFile']('/', bios_fname, bios_files[bios_fname], true, true);
      }
    }
    Module['FS_createDataFile']('/', gamename, game_file, true, true);
  }
};

var update_countdown = function() {
  file_countdown -= 1;

  if (file_countdown === 0) {
    var headID = document.getElementsByTagName("head")[0];
    var newScript = document.createElement('script');
    newScript.type = 'text/javascript';
    newScript.text = js_data;
    headID.appendChild(newScript);
  }
};

// Fetch the BIOS and the game we want to run.
for (var i=0; i < bios_filenames.length; i++) {
  var fname = bios_filenames[i];
  if (fname === "") {
    continue;
  }
  fetch_file('Bios', fname, function(data) { bios_files[fname] = data; update_countdown(); });
}

if (gamename !== "") {
  fetch_file('Game', gamename, function(data) { game_file = data; update_countdown(); });
}

fetch_file('Javascript', 'messcolecovision.js.gz', function(data) { js_data = data; update_countdown(); }, 'text', true);

draw_loading_status();
<commit_msg>Replace double quotes with single quotes<commit_after>var gamename = 'smurfs.zip';
var game_file = null;
var js_data = null;
var bios_filenames = 'coleco.zip'.split(' ');
var bios_files = {};
var requests = [];
var file_countdown = 1;
if (bios_filenames.length !== 0 && bios_filenames[0] !== '') {
  file_countdown += bios_filenames.length;
}
if (gamename !== '') {
  file_countdown++;
}

var newCanvas = document.createElement('canvas');
newCanvas.id = 'canvas';
newCanvas.width = 256;
newCanvas.height = 256;
var holder = document.getElementById('canvasholder');
holder.appendChild(newCanvas);

var draw_loading_status = function() {
  var font_height = 18;
  var line_height = (newCanvas.height - (font_height * 2)) / (requests.length);
  var context = newCanvas.getContext('2d');
  context.clearRect(0, 0, newCanvas.width, newCanvas.height);
  context.font = font_height + 'px sans-serif';
  context.fillStyle = 'Black';
  context.fillText('Loading...', 0, font_height);
  for(var i = 0; i < requests.length; i++) {
     var o = requests[i];
     var y = (line_height * i) + (font_height * 2);
     context.fillStyle = 'Red';
     context.fillRect(0, y, newCanvas.width, line_height);
     context.fillStyle = 'Green';
     context.fillRect(0, y, newCanvas.width * o.progress, line_height);
     context.fillStyle = 'Black';
     context.fillText(o.title + ' ' + Math.round(o.progress * 100) + '%', 0, y + (font_height / 2) + (line_height / 2));
}
}

var progress_fetch_file = function(e) {
  if(e.lengthComputable) {
    e.target.progress = e.loaded / e.total;
    draw_loading_status();
  }
}

var fetch_file = function(title, url, cb, rt, raw) {
  var xhr = new XMLHttpRequest();
  xhr.open('GET', url, true);
  xhr.responseType = rt ? rt : 'arraybuffer';
  xhr.onload = function(e) {
    xhr.progress = 1.0;
    draw_loading_status();
    var ints = raw ? xhr.response :  new Int8Array(xhr.response);
    cb(ints);
  };
  xhr.onprogress = progress_fetch_file;
  xhr.title = title;
  xhr.progress = 0;
  requests.push(xhr);
  xhr.send();
};

var Module = {
  'arguments': ["coleco","-verbose","-rompath",".","-cart",gamename,"-window","-resolution","256x192","-nokeepaspect"],
  print: (function() {
    var element = document.getElementById('output');
    return function(text) {
      text = text.replace(/&/g, '&');
      text = text.replace(/</g, '<');
      text = text.replace(/>/g, '>');
      text = text.replace('\n', '
', 'g');
      element.innerHTML += text + '
';
    };
  })(),
  canvas: document.getElementById('canvas'),
  noInitialRun: false,
  preInit: function() {
    // Load the downloaded binary files into the filesystem.
    for (var bios_fname in bios_files) {
      if (bios_files.hasOwnProperty(bios_fname)) {
        Module['FS_createDataFile']('/', bios_fname, bios_files[bios_fname], true, true);
      }
    }
    Module['FS_createDataFile']('/', gamename, game_file, true, true);
  }
};

var update_countdown = function() {
  file_countdown -= 1;

  if (file_countdown === 0) {
    var headID = document.getElementsByTagName('head')[0];
    var newScript = document.createElement('script');
    newScript.type = 'text/javascript';
    newScript.text = js_data;
    headID.appendChild(newScript);
  }
};

// Fetch the BIOS and the game we want to run.
for (var i=0; i < bios_filenames.length; i++) {
  var fname = bios_filenames[i];
  if (fname === '') {
    continue;
  }
  fetch_file('Bios', fname, function(data) { bios_files[fname] = data; update_countdown(); });
}

if (gamename !== '') {
  fetch_file('Game', gamename, function(data) { game_file = data; update_countdown(); });
}

fetch_file('Javascript', 'messcolecovision.js.gz', function(data) { js_data = data; update_countdown(); }, 'text', true);

draw_loading_status();
<|endoftext|>


<commit_before>/**
 * @file MaterialDropdownSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import DropdownSelect from '../DropdownSelect';
import MaterialProvider from '../MaterialProvider';

import Theme from '../Theme';
import SelectMode from '../_statics/SelectMode';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import ComponentUtil from '../_vendors/ComponentUtil';

class MaterialDropdownSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdownSelect = createRef();
        this.dropdownSelectInstance = null;

        this.state = {
            value: props.value,
            isFocus: false
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.closePopup();
    };

    handleTriggerChange = value => {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    };

    componentDidMount() {
        this.dropdownSelectInstance = this.dropdownSelect && this.dropdownSelect.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate, disabled, required, selectMode,
                ...restProps
            } = this.props,
            {value} = this.state;

        return (
            <MaterialProvider className={classNames('material-dropdown-select', {
                [className]: className
            })}
                              style={style}
                              theme={theme}
                              label={label}
                              isLabelAnimate={isLabelAnimate}
                              hasValue={selectMode === SelectMode.MULTI_SELECT ? value && value.length > 0 : !!value}
                              disabled={disabled}
                              required={required}>
                <DropdownSelect {...restProps}
                                ref={this.dropdownSelect}
                                value={value}
                                selectMode={selectMode}
                                disabled={disabled}
                                onChange={this.handleTriggerChange}/>
            </MaterialProvider>
        );

    }
}

MaterialDropdownSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),

    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.oneOfType([

        // not grouped
        PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

            /**
             * The CSS class name of the list button.
             */
            className: PropTypes.string,

            /**
             * Override the styles of the list button.
             */
            style: PropTypes.object,

            /**
             * The theme of the list button.
             */
            theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

            /**
             * The text value of the list button.Type can be string or number.
             */
            value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The desc value of the list button. Type can be string or number.
             */
            desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * If true, the list button will be disabled.
             */
            disabled: PropTypes.bool,

            /**
             * If true,the button will be have loading effect.
             */
            isLoading: PropTypes.bool,

            /**
             * If true,the element's ripple effect will be disabled.
             */
            disableTouchRipple: PropTypes.bool,

            /**
             * Use this property to display an icon. It will display on the left.
             */
            iconCls: PropTypes.string,

            /**
             * Use this property to display an icon. It will display on the right.
             */
            rightIconCls: PropTypes.string,

            /**
             * You can create a complicated renderer callback instead of value and desc prop.
             */
            renderer: PropTypes.func,

            /**
             * Callback function fired when a list item touch-tapped.
             */
            onClick: PropTypes.func

        }), PropTypes.string, PropTypes.number])),

        // grouped
        PropTypes.array

    ]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the dropDownSelect will be loading.
     */
    isLoading: PropTypes.bool,

    /**
     * The mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    /**
     * If true,the drop-down box will have search input.
     */
    useFilter: PropTypes.bool,

    filterIconCls: PropTypes.string,
    useSelectAll: PropTypes.bool,
    selectAllText: PropTypes.string,

    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    /**
     * The message of no matching option.
     */
    noMatchedMsg: PropTypes.string,

    /**
     * If true,the drop-down box will be have group selection.
     */
    isGrouped: PropTypes.bool,

    required: PropTypes.bool,
    shouldFollowScroll: PropTypes.bool,
    resetPopPositionWait: PropTypes.number,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onWheel: PropTypes.func

};

MaterialDropdownSelect.defaultProps = {

    theme: Theme.DEFAULT,

    isLabelAnimate: true,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: [],
    disabled: false,
    isLoading: false,
    selectMode: SelectMode.SINGLE_SELECT,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',
    useSelectAll: false,
    selectAllText: 'Select All',
    isGrouped: false,
    required: false,
    tipPosition: Position.BOTTOM,

    resetPopPositionWait: 250

};

export default MaterialDropdownSelect;
<commit_msg>update MaterialDropdownSelect<commit_after>/**
 * @file MaterialDropdownSelect component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component, createRef} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import DropdownSelect from '../DropdownSelect';
import MaterialProvider from '../MaterialProvider';

import Theme from '../Theme';
import SelectMode from '../_statics/SelectMode';
import Position from '../_statics/Position';

import Util from '../_vendors/Util';
import ComponentUtil from '../_vendors/ComponentUtil';

class MaterialDropdownSelect extends Component {

    static SelectMode = SelectMode;
    static Theme = Theme;
    static Position = Position;
    static TipPosition = Position;

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.dropdownSelect = createRef();
        this.dropdownSelectInstance = null;

        this.state = {
            value: props.value,
            isFocus: false
        };

    }

    /**
     * public
     */
    startRipple = (e, props) => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.startRipple(e, props);
    };

    /**
     * public
     */
    endRipple = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.endRipple();
    };

    /**
     * public
     */
    triggerRipple = (e, props) => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.triggerRipple(e, props);
    };

    /**
     * public
     */
    resetPopupPosition = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.resetPosition();
    };

    /**
     * public
     */
    openPopup = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.openPopup();
    };

    /**
     * public
     */
    closePopup = () => {
        this.dropdownSelectInstance && this.dropdownSelectInstance.closePopup();
    };

    handleTriggerChange = value => {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    };

    componentDidMount() {
        this.dropdownSelectInstance = this.dropdownSelect && this.dropdownSelect.current;
    }

    static getDerivedStateFromProps(props, state) {
        return {
            prevProps: props,
            value: ComponentUtil.getDerivedState(props, state, 'value')
        };
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate, disabled, required, selectMode,
                ...restProps
            } = this.props,
            {value} = this.state;

        return (
            <MaterialProvider className={classNames('material-dropdown-select', {
                [className]: className
            })}
                              style={style}
                              theme={theme}
                              label={label}
                              isLabelAnimate={isLabelAnimate}
                              hasValue={selectMode === SelectMode.MULTI_SELECT ? value && value.length > 0 : !!value}
                              disabled={disabled}
                              required={required}>
                <DropdownSelect {...restProps}
                                ref={this.dropdownSelect}
                                value={value}
                                selectMode={selectMode}
                                disabled={disabled}
                                onChange={this.handleTriggerChange}/>
            </MaterialProvider>
        );

    }
}

MaterialDropdownSelect.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * The class name of the popup element.
     */
    popupClassName: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Override the styles of the popup element.
     */
    popupStyle: PropTypes.object,

    /**
     * The theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    position: PropTypes.oneOf(Util.enumerateValue(Position)),

    /**
     * The name of the dropDownSelect.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.any,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The value of the dropDownSelect.
     */
    value: PropTypes.any,

    /**
     * The placeholder of the dropDownSelect.
     */
    placeholder: PropTypes.string,

    title: PropTypes.string,
    tip: PropTypes.string,
    tipPosition: PropTypes.oneOf(Util.enumerateValue(Position)),

    rightIconCls: PropTypes.string,

    /**
     * The options data.
     */
    data: PropTypes.oneOfType([

        // not grouped
        PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.shape({

            /**
             * The CSS class name of the list button.
             */
            className: PropTypes.string,

            /**
             * Override the styles of the list button.
             */
            style: PropTypes.object,

            /**
             * The theme of the list button.
             */
            theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

            /**
             * The text value of the list button.Type can be string or number.
             */
            value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * The desc value of the list button. Type can be string or number.
             */
            desc: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

            /**
             * If true, the list button will be disabled.
             */
            disabled: PropTypes.bool,

            /**
             * If true,the button will be have loading effect.
             */
            isLoading: PropTypes.bool,

            /**
             * If true,the element's ripple effect will be disabled.
             */
            disableTouchRipple: PropTypes.bool,

            /**
             * Use this property to display an icon. It will display on the left.
             */
            iconCls: PropTypes.string,

            /**
             * Use this property to display an icon. It will display on the right.
             */
            rightIconCls: PropTypes.string,

            /**
             * You can create a complicated renderer callback instead of value and desc prop.
             */
            renderer: PropTypes.func,

            /**
             * Callback function fired when a list item touch-tapped.
             */
            onClick: PropTypes.func

        }), PropTypes.string, PropTypes.number])),

        // grouped
        PropTypes.array

    ]),

    /**
     * The invalid message of dropDownSelect.
     */
    invalidMsg: PropTypes.string,

    /**
     * If true,the dropDownSelect will be disabled.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the dropDownSelect will be loading.
     */
    isLoading: PropTypes.bool,

    /**
     * The mode of listItem.Can be normal,checkbox.
     */
    selectMode: PropTypes.oneOf(Util.enumerateValue(SelectMode)),

    /**
     * The value field name in data. (default: "value")
     */
    valueField: PropTypes.string,

    /**
     * The display field name in data. (default: "text")
     */
    displayField: PropTypes.string,

    /**
     * The description field name in data. (default: "desc")
     */
    descriptionField: PropTypes.string,

    /**
     * The message of the dropDownSelect.
     */
    infoMsg: PropTypes.string,

    /**
     * Use this function to format the options's text.
     */
    textFormat: PropTypes.func,

    /**
     * If true,the drop-down box automatically closed after selection.
     */
    autoClose: PropTypes.bool,

    /**
     * If true,the drop-down box will have search input.
     */
    useFilter: PropTypes.bool,

    filterIconCls: PropTypes.string,
    filterPlaceholder: PropTypes.string,
    useSelectAll: PropTypes.bool,
    selectAllText: PropTypes.string,

    radioUncheckedIconCls: PropTypes.string,
    radioCheckedIconCls: PropTypes.string,
    checkboxUncheckedIconCls: PropTypes.string,
    checkboxCheckedIconCls: PropTypes.string,
    checkboxIndeterminateIconCls: PropTypes.string,

    /**
     * The message of no matching option.
     */
    noMatchedMsg: PropTypes.string,

    /**
     * If true,the drop-down box will be have group selection.
     */
    isGrouped: PropTypes.bool,

    required: PropTypes.bool,
    shouldFollowScroll: PropTypes.bool,
    resetPopPositionWait: PropTypes.number,

    /**
     * Callback function fired when the button is touch-tapped.
     */
    onItemClick: PropTypes.func,

    /**
     * Callback function fired when the popup is closed.
     */
    onClosePopup: PropTypes.func,

    /**
     * Callback function fired when a menu item is selected.
     */
    onChange: PropTypes.func,

    onWheel: PropTypes.func

};

MaterialDropdownSelect.defaultProps = {

    theme: Theme.DEFAULT,

    isLabelAnimate: true,
    placeholder: 'Please select ...',
    rightIconCls: 'fas fa-angle-down',
    data: [],
    disabled: false,
    isLoading: false,
    selectMode: SelectMode.SINGLE_SELECT,

    valueField: 'value',
    displayField: 'text',
    descriptionField: 'desc',

    autoClose: true,
    useFilter: false,
    filterIconCls: 'fas fa-search',
    filterPlaceholder: 'Search ...',
    useSelectAll: false,
    selectAllText: 'Select All',
    isGrouped: false,
    required: false,
    tipPosition: Position.BOTTOM,

    resetPopPositionWait: 250

};

export default MaterialDropdownSelect;
<|endoftext|>


<commit_before>let co = require('co'),
	jwt = require('jsonwebtoken')

class TokenManager{
	constructor({generalStore}) {
		this.generalStore = generalStore
	}

	signToken({userId, secret, expiresInMinutes}) {
		return new Promise((resolve, reject) => {
			if (expiresInMinutes) {
				jwt.sign({id: userId}, secret, { expiresIn: expiresInMinutes * 60 }, (err, token) => {
					if (err) {
						reject({customMessage: 'Failed to sign token.', status: 401})
						return;
					}
					resolve(token)
				})
			}
			jwt.sign({id: userId}, secret, null, (err, token) => {
				if (err) {
					reject({customMessage: 'Failed to sign token.', status: 401})
					return;
				}
				resolve(token)
			})
		})
	}

	verifyToken({token, secret}) {
		return new Promise((resolve, reject) => {
			jwt.verify(token, secret, (err, decoded) => {
				if (err) {
					if (err.name === 'TokenExpiredError') {
						reject({tokenExpired: true})
						return;
					}
					reject({customMessage: 'Failed to verify token.', status: 401})
					return;
				}
				resolve(decoded)
			})
		})
	}

	createToken({type, userId, secret, moduleName, expiresInMinutes}) {
		let instance = this
		return co(function* () {
			if (type === 'access') {
				let token = yield instance.signToken({userId, secret, expiresInMinutes}),
					currentToken = instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`)
				if (currentToken) {
					yield instance.generalStore.removeEntry(`${moduleName}user${userId}AccessToken`)
					yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentToken}`)
				}
				yield instance.generalStore.storeEntry(`${moduleName}user${userId}AccessToken`, token)
				return token
			}

			if (type === 'refresh') {
				let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`)
				if (!currentAccessToken) {
					throw {customMessage: 'No access token to create a refresh token for.'}
				}

				let	token = yield instance.signToken({userId, secret}),
					currentToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
				if (currentToken) {
					yield instance.generalStore.storeEntry(`${moduleName}refreshTokenBlacklist-${currentToken}`)
					yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
				}
				yield instance.generalStore.storeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`, token)
				return token
			}

			return null
		})
	}

	validate() {
		return (req, res, next) => {
			let moduleName = '',
				config = {},
				originalModuleName = '',
				originalConfig = ''
			try {
				moduleName = req.locals.moduleName
				originalModuleName = req.locals.moduleName
				config = req.locals.cfg[moduleName]
				originalConfig = req.locals.cfg[moduleName]
				if (!req.headers['authorization']) {
					throw {customMessage: 'No access token provided.', status: 401}
				}
				if (config.useModuleConfigForAuthTokens) {
					moduleName = config.useModuleConfigForAuthTokens
					config = req.locals.cfg[config.useModuleConfigForAuthTokens]
				}

				let tokens = req.headers['authorization'].split(' '),
					instance = this
				if ((tokens[0] !== 'Bearer') || (tokens[1] === 'undefined')) {
					throw {customMessage: 'No access token provided.', status: 401}
				}

				co(function* () {
					try {
						let decoded = yield instance.verifyToken({token: tokens[1], secret: config.jwt.secret})
						if (!decoded.id) {
							throw {customMessage: 'Invalid access token.', status: 401}
						}

						let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${decoded.id}AccessToken`),
							currentAccessTokenBlacklisted = yield instance.generalStore.getStoredEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
						if ((currentAccessToken !== tokens[1]) || currentAccessTokenBlacklisted) {
							throw {customMessage: 'Invalid access token.', status: 401}
						}

						req.user = {id: decoded.id}
						return true
					} catch(e) {
						try {
							if (!e.tokenExpired) {
								throw e
							}

							if (tokens[2] === 'undefined') {
								throw {customMessage: `Access token expired.${config.jwt.useRefreshTokens ? 'No refresh token provided.' : ''}`, status: 401}
							}

							let decoded = yield instance.verifyToken({token: tokens[2], secret: config.jwt.secret})
							if (!decoded.id) {
								throw {customMessage: 'Invalid access token. Invalid refresh token.', status: 401}
							}

							let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${decoded.id}AccessToken`),
								currentRefreshToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`),
								currentRefreshTokenBlacklisted = yield instance.generalStore.getStoredEntry(`${moduleName}refreshTokenBlacklist-${currentAccessToken}`)
							yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
							if ((currentRefreshToken !== tokens[2]) || currentRefreshTokenBlacklisted) {
								throw {customMessage: 'Invalid access token. Invalid refresh token.', status: 401}
							}

							let newAccessToken = yield req.locals.tokenManager.createToken({type: 'access', userId: user.id, secret: config.jwt.secret, expiresInMinutes: config.jwt.accessTokenExpiresInMinutes})
							yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
							yield instance.generalStore.storeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${newAccessToken}`, currentRefreshToken)

							req.user = {id: decoded.id}
							res.set('authorization-newaccesstoken', newAccessToken)
							return true
						} catch (innerError) {
							req.user = null
							req.locals.logger.error(innerError)
							let status = innerError.status || 500,
								message = innerError.customMessage || 'An internal server error has occurred.'
							if (innerError.tokenExpired) {
								status = 401
								message = 'Access token expired. Refresh token expired.'
							}
							if (config.passErrorToNext || (originalConfig && originalConfig.passErrorToNext)) {
								next({status, message})
								return false
							}
							res.status(status).json({error: message})
							return false
						}
					}
				}).then((result) => {
					if (result) {
						next()
					}
				}, (error) => {
					throw error
				})
			} catch(e) {
				req.user = null
				let response = {},
					status = e.status || req.locals.errorStatus || 500,
					message = e.customMessage || 'An internal server error has occurred.'
				if (req.locals.settings.responseType === 'serviceName') {
					response = {serviceName: req.locals.serviceName, data: null, message}
				} else {
					response = {message}
				}
				if (config.passErrorToNext || (originalConfig && originalConfig.passErrorToNext)) {
					next({status, message})
					return
				}
				req.locals.logger.error(e)
				res.status(status).json(response)
			}
		}
	}

	deleteTokens({userId, moduleName}) {
		let instance = this
		return co(function* () {
			let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`),
				currentRefreshToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
			yield instance.generalStore.removeEntry(`${moduleName}user${userId}AccessToken`)
			yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
			yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
			yield instance.generalStore.storeEntry(`${moduleName}refreshTokenBlacklist-${currentRefreshToken}`)
			return true
		})
	}
}

module.exports = TokenManager
<commit_msg>updates to the tokenManager - blacklists now work correctly<commit_after>let co = require('co'),
	jwt = require('jsonwebtoken')

class TokenManager{
	constructor({generalStore}) {
		this.generalStore = generalStore
	}

	signToken({userId, secret, expiresInMinutes}) {
		return new Promise((resolve, reject) => {
			if (expiresInMinutes) {
				jwt.sign({id: userId}, secret, { expiresIn: expiresInMinutes * 60 }, (err, token) => {
					if (err) {
						reject({customMessage: 'Failed to sign token.', status: 401})
						return;
					}
					resolve(token)
				})
			}
			jwt.sign({id: userId}, secret, null, (err, token) => {
				if (err) {
					reject({customMessage: 'Failed to sign token.', status: 401})
					return;
				}
				resolve(token)
			})
		})
	}

	verifyToken({token, secret}) {
		return new Promise((resolve, reject) => {
			jwt.verify(token, secret, (err, decoded) => {
				if (err) {
					if (err.name === 'TokenExpiredError') {
						reject({tokenExpired: true})
						return;
					}
					reject({customMessage: 'Failed to verify token.', status: 401})
					return;
				}
				resolve(decoded)
			})
		})
	}

	createToken({type, userId, secret, moduleName, expiresInMinutes}) {
		let instance = this
		return co(function* () {
			if (type === 'access') {
				let token = yield instance.signToken({userId, secret, expiresInMinutes}),
					currentToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`)
				if (currentToken) {
					yield instance.generalStore.removeEntry(`${moduleName}user${userId}AccessToken`)
					yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentToken}`, true)
				}
				yield instance.generalStore.storeEntry(`${moduleName}user${userId}AccessToken`, token)
				return token
			}

			if (type === 'refresh') {
				let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`)
				if (!currentAccessToken) {
					throw {customMessage: 'No access token to create a refresh token for.'}
				}

				let	token = yield instance.signToken({userId, secret}),
					currentToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
				if (currentToken) {
					yield instance.generalStore.storeEntry(`${moduleName}refreshTokenBlacklist-${currentToken}`, true)
					yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
				}
				yield instance.generalStore.storeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`, token)
				return token
			}

			return null
		})
	}

	validate() {
		return (req, res, next) => {
			let moduleName = '',
				config = {},
				originalModuleName = '',
				originalConfig = ''
			try {
				moduleName = req.locals.moduleName
				originalModuleName = req.locals.moduleName
				config = req.locals.cfg[moduleName]
				originalConfig = req.locals.cfg[moduleName]
				if (!req.headers['authorization']) {
					throw {customMessage: 'No access token provided.', status: 401}
				}
				if (config.useModuleConfigForAuthTokens) {
					moduleName = config.useModuleConfigForAuthTokens
					config = req.locals.cfg[config.useModuleConfigForAuthTokens]
				}

				let tokens = req.headers['authorization'].split(' '),
					instance = this
				if ((tokens[0] !== 'Bearer') || (tokens[1] === 'undefined')) {
					throw {customMessage: 'No access token provided.', status: 401}
				}

				co(function* () {
					try {
						let decoded = yield instance.verifyToken({token: tokens[1], secret: config.jwt.secret})
						if (!decoded.id) {
							throw {customMessage: 'Invalid access token.', status: 401}
						}

						let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${decoded.id}AccessToken`),
							currentAccessTokenBlacklisted = yield instance.generalStore.getStoredEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
						if ((currentAccessToken !== tokens[1]) || currentAccessTokenBlacklisted) {
							throw {customMessage: 'Invalid access token.', status: 401}
						}

						req.user = {id: decoded.id}
						return true
					} catch(e) {
						try {
							if (!e.tokenExpired) {
								throw e
							}

							if (tokens[2] === 'undefined') {
								throw {customMessage: `Access token expired.${config.jwt.useRefreshTokens ? 'No refresh token provided.' : ''}`, status: 401}
							}

							let decoded = yield instance.verifyToken({token: tokens[2], secret: config.jwt.secret})
							if (!decoded.id) {
								throw {customMessage: 'Invalid access token. Invalid refresh token.', status: 401}
							}

							let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${decoded.id}AccessToken`),
								currentRefreshToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`),
								currentRefreshTokenBlacklisted = yield instance.generalStore.getStoredEntry(`${moduleName}refreshTokenBlacklist-${currentAccessToken}`)
							yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
							if ((currentRefreshToken !== tokens[2]) || currentRefreshTokenBlacklisted) {
								throw {customMessage: 'Invalid access token. Invalid refresh token.', status: 401}
							}

							let newAccessToken = yield req.locals.tokenManager.createToken({type: 'access', userId: user.id, secret: config.jwt.secret, expiresInMinutes: config.jwt.accessTokenExpiresInMinutes})
							yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
							yield instance.generalStore.storeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${newAccessToken}`, currentRefreshToken)

							req.user = {id: decoded.id}
							res.set('authorization-newaccesstoken', newAccessToken)
							return true
						} catch (innerError) {
							req.user = null
							req.locals.logger.error(innerError)
							let status = innerError.status || 500,
								message = innerError.customMessage || 'An internal server error has occurred.'
							if (innerError.tokenExpired) {
								status = 401
								message = 'Access token expired. Refresh token expired.'
							}
							if (config.passErrorToNext || (originalConfig && originalConfig.passErrorToNext)) {
								next({status, message})
								return false
							}
							res.status(status).json({error: message})
							return false
						}
					}
				}).then((result) => {
					if (result) {
						next()
					}
				}, (error) => {
					throw error
				})
			} catch(e) {
				req.user = null
				let response = {},
					status = e.status || req.locals.errorStatus || 500,
					message = e.customMessage || 'An internal server error has occurred.'
				if (req.locals.settings.responseType === 'serviceName') {
					response = {serviceName: req.locals.serviceName, data: null, message}
				} else {
					response = {message}
				}
				if (config.passErrorToNext || (originalConfig && originalConfig.passErrorToNext)) {
					next({status, message})
					return
				}
				req.locals.logger.error(e)
				res.status(status).json(response)
			}
		}
	}

	deleteTokens({userId, moduleName}) {
		let instance = this
		return co(function* () {
			let currentAccessToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}AccessToken`),
				currentRefreshToken = yield instance.generalStore.getStoredEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
			yield instance.generalStore.removeEntry(`${moduleName}user${userId}AccessToken`)
			yield instance.generalStore.removeEntry(`${moduleName}user${userId}RefreshTokenForAccessToken${currentAccessToken}`)
			yield instance.generalStore.storeEntry(`${moduleName}accessTokenBlacklist-${currentAccessToken}`)
			yield instance.generalStore.storeEntry(`${moduleName}refreshTokenBlacklist-${currentRefreshToken}`)
			return true
		})
	}
}

module.exports = TokenManager
<|endoftext|>


<commit_before>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      jasmine: {
        test: {
          src: './public/js/*.js',
          options: {
            vendor: [
              'public/js/lib/jquery/jquery-2.1.1.js',
              'node_modules/jasmine-jquery/lib/jasmine-jquery.js'
            ],
            specs: 'test/*-spec.js'
          }
        }
      }
  });

  grunt.loadNpmTasks('grunt-contrib-jasmine');
}
<commit_msg>Updated Gruntfile to save SpecRunner<commit_after>module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      jasmine: {
        test: {
          src: './public/js/*.js',
          options: {
            vendor: [
              'public/js/lib/jquery/jquery-2.1.1.js',
              'node_modules/jasmine-jquery/lib/jasmine-jquery.js'
            ],
            keepRunner: true,
            specs: 'test/*-spec.js'
          }
        }
      }
  });

  grunt.loadNpmTasks('grunt-contrib-jasmine');
}
<|endoftext|>


<commit_before>var test = require('tape');

var u = require('../util.js');
var wkt = require('terraformer-wkt-parser');

test('create request url', function(t) {
  t.plan(2);

  t.equal(u.createRequestURL({ limit: 10 }, 'endpoint'), 'http://api.effechecka.org/endpoint?limit=10');
  t.equal(u.createRequestURL({ limit: 10, foo: 'bar' }, 'endpoint'), 'http://api.effechecka.org/endpoint?limit=10&foo=bar');
});

test('source,id to url', function(t) {
  t.plan(4);

  var inat = { source: 'inaturalist', id: 'http://www.inaturalist.org/observations/1035877' };
  var gbif = { source: 'gbif', id: 'URN:catalog:CLO:EBIRD:OBS153095840' };
  var idigbio = { source: 'idigbio', id: 'urn:catalog:ucmp:p:153071' };

  t.equal(u.urlForOccurrence(inat), 'http://www.inaturalist.org/observations/1035877');
  t.equal(u.urlForOccurrence(gbif), 'http://www.gbif.org/occurrence/search?OCCURRENCE_ID=URN%3Acatalog%3ACLO%3AEBIRD%3AOBS153095840');

  var idigbioExpected = 'http://portal.idigbio.org/search?rq={%22occurrenceid%22:%22urn%3Acatalog%3Aucmp%3Ap%3A153071%22}';
  t.equal(u.urlForOccurrence(idigbio), idigbioExpected);

  var unknown = { source: 'something', id: 'other' };
  t.equal(u.urlForOccurrence(unknown), 'http://archive.effechecka.org/job/something');
});

test('extract most specific taxon name from ordered path', function (t) {
    t.plan(2);
    t.equal(u.lastNameFromPath('one | two | three |'), 'three');
    t.equal(u.lastNameFromPath('one | two | three'), 'three');
});

test('clamp lng', function (t) {
    t.plan(7);
    t.equal(u.normLng(0), 0);
    t.equal(u.normLng(90), 90);
    t.equal(u.normLng(180), 180);
    t.equal(u.normLng(-90), -90);
    t.equal(u.normLng(-180), -180);
    t.equal(u.normLng(-270), 90);
    t.equal(u.normLng(360), 0);
});

test('wkt envelope', function (t) {
    t.plan(2);
    t.equal(u.wktEnvelope({ _northEast: { lat: 12, lng: 1 }, _southWest: { lat: 10, lng: 0 }}), 'ENVELOPE(0,1,12,10)');
    t.equal(u.wktEnvelope({ _northEast: { lat: 12, lng: -90 }, _southWest: { lat: 10, lng: 90 }}), 'ENVELOPE(90,-90,12,10)');
});

test('normalize bounds', function (t) {
    t.plan(1);
    var arcticCanadaRussia = { _northEast: {lat: 87.04309838968054, lng: 87.1875}, _southWest: { lat: 55.7765730186677, lng: -243.28125}};
    var expectedBounds = { _northEast: {lat: 87.04309838968054, lng: 87.1875}, _southWest: { lat: 55.7765730186677, lng: 116.71875}};
    t.deepEqual(u.normBounds(arcticCanadaRussia), expectedBounds);
});

test('capitalize', function (t) {
    t.plan(3);
    t.equal(u.capitalize('one two'), 'One two');
    t.equal(u.capitalize('one'), 'One');
    t.equal(u.capitalize('one Two'), 'One Two');
});

test('collection wkt to list', function (t) {
    t.plan(1);
    var collectionWkt = "GEOMETRYCOLLECTION(POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8)),POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1)))";
    var expectedList = [ "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))", "POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1))"];

    t.deepEqual(u.geometryCollectionToWktStrings(collectionWkt), expectedList);
});

test('no-collection wkt to list', function (t) {
    t.plan(1);
    var collectionWkt = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))";
    var expectedList = [ "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))"];

    t.deepEqual(u.geometryCollectionToWktStrings(collectionWkt), expectedList);
});

test('wkt list to collection', function (t) {
    t.plan(1);
    var wktStrings = ["POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))", "POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1))"];
    var expectedCollectionWkt = "GEOMETRYCOLLECTION(POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8)),POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1)))";

    t.equal(u.wktStringsToGeometryCollection(wktStrings), expectedCollectionWkt);
});

test('single item wkt list to collection', function (t) {
    t.plan(1);
    var wktStrings = ["POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))"];
    var expectedCollectionWkt = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))";

    t.equal(u.wktStringsToGeometryCollection(wktStrings), expectedCollectionWkt);
});

test('wkt envelope to polygon', function (t) {
    t.plan(1);
    var exectedPolygon = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3 41.8, -71.8 41.8))";
    var envelope = "ENVELOPE(-71.8,-70.3,42.8,41.8)";

    t.equal(u.wktEnvelopeToPolygon(envelope), exectedPolygon);
});
<commit_msg>update api endpoint<commit_after>var test = require('tape');

var u = require('../util.js');
var wkt = require('terraformer-wkt-parser');

test('create request url', function(t) {
  t.plan(2);

  t.equal(u.createRequestURL({ limit: 10 }, 'endpoint'), 'http://api.guoda.bio/endpoint?limit=10');
  t.equal(u.createRequestURL({ limit: 10, foo: 'bar' }, 'endpoint'), 'http://api.guoda.bio/endpoint?limit=10&foo=bar');
});

test('source,id to url', function(t) {
  t.plan(4);

  var inat = { source: 'inaturalist', id: 'http://www.inaturalist.org/observations/1035877' };
  var gbif = { source: 'gbif', id: 'URN:catalog:CLO:EBIRD:OBS153095840' };
  var idigbio = { source: 'idigbio', id: 'urn:catalog:ucmp:p:153071' };

  t.equal(u.urlForOccurrence(inat), 'http://www.inaturalist.org/observations/1035877');
  t.equal(u.urlForOccurrence(gbif), 'http://www.gbif.org/occurrence/search?OCCURRENCE_ID=URN%3Acatalog%3ACLO%3AEBIRD%3AOBS153095840');

  var idigbioExpected = 'http://portal.idigbio.org/search?rq={%22occurrenceid%22:%22urn%3Acatalog%3Aucmp%3Ap%3A153071%22}';
  t.equal(u.urlForOccurrence(idigbio), idigbioExpected);

  var unknown = { source: 'something', id: 'other' };
  t.equal(u.urlForOccurrence(unknown), 'http://archive.guoda.bio/job/something');
});

test('extract most specific taxon name from ordered path', function (t) {
    t.plan(2);
    t.equal(u.lastNameFromPath('one | two | three |'), 'three');
    t.equal(u.lastNameFromPath('one | two | three'), 'three');
});

test('clamp lng', function (t) {
    t.plan(7);
    t.equal(u.normLng(0), 0);
    t.equal(u.normLng(90), 90);
    t.equal(u.normLng(180), 180);
    t.equal(u.normLng(-90), -90);
    t.equal(u.normLng(-180), -180);
    t.equal(u.normLng(-270), 90);
    t.equal(u.normLng(360), 0);
});

test('wkt envelope', function (t) {
    t.plan(2);
    t.equal(u.wktEnvelope({ _northEast: { lat: 12, lng: 1 }, _southWest: { lat: 10, lng: 0 }}), 'ENVELOPE(0,1,12,10)');
    t.equal(u.wktEnvelope({ _northEast: { lat: 12, lng: -90 }, _southWest: { lat: 10, lng: 90 }}), 'ENVELOPE(90,-90,12,10)');
});

test('normalize bounds', function (t) {
    t.plan(1);
    var arcticCanadaRussia = { _northEast: {lat: 87.04309838968054, lng: 87.1875}, _southWest: { lat: 55.7765730186677, lng: -243.28125}};
    var expectedBounds = { _northEast: {lat: 87.04309838968054, lng: 87.1875}, _southWest: { lat: 55.7765730186677, lng: 116.71875}};
    t.deepEqual(u.normBounds(arcticCanadaRussia), expectedBounds);
});

test('capitalize', function (t) {
    t.plan(3);
    t.equal(u.capitalize('one two'), 'One two');
    t.equal(u.capitalize('one'), 'One');
    t.equal(u.capitalize('one Two'), 'One Two');
});

test('collection wkt to list', function (t) {
    t.plan(1);
    var collectionWkt = "GEOMETRYCOLLECTION(POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8)),POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1)))";
    var expectedList = [ "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))", "POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1))"];

    t.deepEqual(u.geometryCollectionToWktStrings(collectionWkt), expectedList);
});

test('no-collection wkt to list', function (t) {
    t.plan(1);
    var collectionWkt = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))";
    var expectedList = [ "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))"];

    t.deepEqual(u.geometryCollectionToWktStrings(collectionWkt), expectedList);
});

test('wkt list to collection', function (t) {
    t.plan(1);
    var wktStrings = ["POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))", "POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1))"];
    var expectedCollectionWkt = "GEOMETRYCOLLECTION(POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8)),POLYGON ((-72.6 43.1, -72.6 43.5, -71.6 43.5, -71.6 43.1, -72.6 43.1)))";

    t.equal(u.wktStringsToGeometryCollection(wktStrings), expectedCollectionWkt);
});

test('single item wkt list to collection', function (t) {
    t.plan(1);
    var wktStrings = ["POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))"];
    var expectedCollectionWkt = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3125 41.8, -71.8 41.8))";

    t.equal(u.wktStringsToGeometryCollection(wktStrings), expectedCollectionWkt);
});

test('wkt envelope to polygon', function (t) {
    t.plan(1);
    var exectedPolygon = "POLYGON ((-71.8 41.8, -71.8 42.8, -70.3 42.8, -70.3 41.8, -71.8 41.8))";
    var envelope = "ENVELOPE(-71.8,-70.3,42.8,41.8)";

    t.equal(u.wktEnvelopeToPolygon(envelope), exectedPolygon);
});
<|endoftext|>


<commit_before>export default {
  lang: 'pt',
  label: {
    clear: 'Limpar',
    ok: 'OK',
    cancel: 'Cancelar',
    close: 'Fechar',
    set: 'Marcar',
    select: 'Escolher',
    reset: 'Limpar',
    remove: 'Remover',
    update: 'Atualizar',
    create: 'Criar',
    search: 'Procurar',
    filter: 'Filtrar',
    refresh: 'Recarregar'
  },
  date: {
    days: 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
    daysShort: 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
    months: 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
    monthsShort: 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
    firstDayOfWeek: 0, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Puxe para recarregar',
    release: 'Solte para recarregar',
    refresh: 'A carregar...'
  },
  table: {
    noData: 'Sem dados disponíveis',
    noResults: 'Não foi encontrado nenhum resultado',
    loading: 'A carregar...',
    selectedRecords: function (rows) {
      return rows > 0
        ? rows + ' linha' + (rows === 1 ? ' selecionada' : 's selecionadas') + '.'
        : 'Nenhuma linha selecionada.'
    },
    recordsPerPage: 'Linhas por página:',
    allRows: 'Todas',
    pagination: function (start, end, total) {
      return start + '-' + end + ' de ' + total
    },
    columns: 'Colunas'
  },
  editor: {
    url: 'URL',
    bold: 'Negrito',
    italic: 'Itálico',
    strikethrough: 'Rasurado',
    underline: 'Sublinhado',
    unorderedList: 'Lista não-ordenada',
    orderedList: 'Lista ordenada',
    subscript: 'Subscrito',
    superscript: 'Sobrescrito',
    hyperlink: 'Hyperlink',
    toggleFullscreen: 'Maximizar',
    quote: 'Citação',
    left: 'Alinhado à esquerda',
    center: 'Alinhado ao centro',
    right: 'Alinhado à direita',
    justify: 'Justificado',
    print: 'Imprimir',
    outdent: 'Diminuir indentação',
    indent: 'Aumentar indentação',
    removeFormat: 'Remover formatação',
    formatting: 'Formatação',
    fontSize: 'Tamanho do tipo de letra',
    align: 'Alinhar',
    hr: 'Inserir linha horizontal',
    undo: 'Desfazer',
    redo: 'Refazer',
    header1: 'Cabeçalho 1',
    header2: 'Cabeçalho 2',
    header3: 'Cabeçalho 3',
    header4: 'Cabeçalho 4',
    header5: 'Cabeçalho 5',
    header6: 'Cabeçalho 6',
    paragraph: 'Parágrafo',
    code: 'Código',
    size1: 'Muito pequeno',
    size2: 'Pequeno',
    size3: 'Normal',
    size4: 'Médio',
    size5: 'Grande',
    size6: 'Enorme',
    size7: 'Máximo',
    defaultFont: 'Tipo de letra padrão'
  },
  tree: {
    noNodes: 'Sem nós disponíveis',
    noResults: 'Nenhum resultado encontrado'
  }
}
<commit_msg>First day of week for Portuguese is Monday<commit_after>export default {
  lang: 'pt',
  label: {
    clear: 'Limpar',
    ok: 'OK',
    cancel: 'Cancelar',
    close: 'Fechar',
    set: 'Marcar',
    select: 'Escolher',
    reset: 'Limpar',
    remove: 'Remover',
    update: 'Atualizar',
    create: 'Criar',
    search: 'Procurar',
    filter: 'Filtrar',
    refresh: 'Recarregar'
  },
  date: {
    days: 'Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado'.split('_'),
    daysShort: 'Dom_Seg_Ter_Qua_Qui_Sex_Sáb'.split('_'),
    months: 'Janeiro_Fevereiro_Março_Abril_Maio_Junho_Julho_Agosto_Setembro_Outubro_Novembro_Dezembro'.split('_'),
    monthsShort: 'Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez'.split('_'),
    firstDayOfWeek: 1, // 0-6, 0 - Sunday, 1 Monday, ...
    format24h: true
  },
  pullToRefresh: {
    pull: 'Puxe para recarregar',
    release: 'Solte para recarregar',
    refresh: 'A carregar...'
  },
  table: {
    noData: 'Sem dados disponíveis',
    noResults: 'Não foi encontrado nenhum resultado',
    loading: 'A carregar...',
    selectedRecords: function (rows) {
      return rows > 0
        ? rows + ' linha' + (rows === 1 ? ' selecionada' : 's selecionadas') + '.'
        : 'Nenhuma linha selecionada.'
    },
    recordsPerPage: 'Linhas por página:',
    allRows: 'Todas',
    pagination: function (start, end, total) {
      return start + '-' + end + ' de ' + total
    },
    columns: 'Colunas'
  },
  editor: {
    url: 'URL',
    bold: 'Negrito',
    italic: 'Itálico',
    strikethrough: 'Rasurado',
    underline: 'Sublinhado',
    unorderedList: 'Lista não-ordenada',
    orderedList: 'Lista ordenada',
    subscript: 'Subscrito',
    superscript: 'Sobrescrito',
    hyperlink: 'Hyperlink',
    toggleFullscreen: 'Maximizar',
    quote: 'Citação',
    left: 'Alinhado à esquerda',
    center: 'Alinhado ao centro',
    right: 'Alinhado à direita',
    justify: 'Justificado',
    print: 'Imprimir',
    outdent: 'Diminuir indentação',
    indent: 'Aumentar indentação',
    removeFormat: 'Remover formatação',
    formatting: 'Formatação',
    fontSize: 'Tamanho do tipo de letra',
    align: 'Alinhar',
    hr: 'Inserir linha horizontal',
    undo: 'Desfazer',
    redo: 'Refazer',
    header1: 'Cabeçalho 1',
    header2: 'Cabeçalho 2',
    header3: 'Cabeçalho 3',
    header4: 'Cabeçalho 4',
    header5: 'Cabeçalho 5',
    header6: 'Cabeçalho 6',
    paragraph: 'Parágrafo',
    code: 'Código',
    size1: 'Muito pequeno',
    size2: 'Pequeno',
    size3: 'Normal',
    size4: 'Médio',
    size5: 'Grande',
    size6: 'Enorme',
    size7: 'Máximo',
    defaultFont: 'Tipo de letra padrão'
  },
  tree: {
    noNodes: 'Sem nós disponíveis',
    noResults: 'Nenhum resultado encontrado'
  }
}
<|endoftext|>


<commit_before>var PIXI = require("pixi.js");
var smoothstep = require("smoothstep");
var tilePIXI = require("./tilePIXI");

var goblinTexture = PIXI.Texture.fromImage("/assets/img/goblin.png");
var minesTextureTile = PIXI.Texture.fromImage("/assets/img/mines.png");

var tilePIXI32 = tilePIXI(32);
var mineTextures = [
  tilePIXI32(minesTextureTile, 0, 0),
  tilePIXI32(minesTextureTile, 0, 3),
  tilePIXI32(minesTextureTile, 0, 4),
  tilePIXI32(minesTextureTile, 0, 2),
  tilePIXI32(minesTextureTile, 0, 1)
];

function setSpriteOwner (sprite, owner) {
  if (owner === "-") {
    sprite.setTexture(mineTextures[0]);
    sprite.position.y = 0;
  }
  else {
    sprite.setTexture(mineTextures[parseInt(owner, 10)]);
    sprite.position.y = -8;
  }
}

function Mine (owner) {
  PIXI.DisplayObjectContainer.call(this);
  this.previousSprite = new PIXI.Sprite(mineTextures[0]);
  this.currentSprite = new PIXI.Sprite(mineTextures[0]);
  this.goblin = new PIXI.Sprite(goblinTexture);
  this.goblin.position.y = -8;
  setSpriteOwner(this.currentSprite, owner);
  this.addChild(this.previousSprite);
  this.addChild(this.currentSprite);
  this.addChild(this.goblin);
  this.updateOwner(owner);
}
Mine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
Mine.prototype.constructor = Mine;

Mine.prototype.updateOwner = function (owner, interpolationTime) {
  // TODO : improve that with meta ?
  if (owner === this.currentOwner) return;
  this.previousOwner = this.currentOwner;
  this.currentOwner = owner;
  this.updatedTime = Date.now();
  this.interpolationTime = this.previousOwner && interpolationTime;

  setSpriteOwner(this.currentSprite, this.currentOwner);
  setSpriteOwner(this.previousSprite, this.previousOwner);
  if (!this.interpolationTime) {
    this.previousSprite.alpha = 0;
    this.currentSprite.alpha = 1;
  }
  this.goblin.alpha = (this.currentOwner === "-" ? 1 : 0);
};

Mine.prototype.render = function () {
  if (!this.interpolationTime) return;
  var p = smoothstep(0, this.interpolationTime, Date.now()-this.updatedTime);
  this.previousSprite.alpha = 1-p;
  this.currentSprite.alpha = p;
};

module.exports = Mine;
<commit_msg>fix Mine positionning<commit_after>var PIXI = require("pixi.js");
var smoothstep = require("smoothstep");
var tilePIXI = require("./tilePIXI");

var goblinTexture = PIXI.Texture.fromImage("/assets/img/goblin.png");
var minesTextureTile = PIXI.Texture.fromImage("/assets/img/mines.png");

var tilePIXI32 = tilePIXI(32);
var mineTextures = [
  tilePIXI32(minesTextureTile, 0, 0),
  tilePIXI32(minesTextureTile, 0, 3),
  tilePIXI32(minesTextureTile, 0, 4),
  tilePIXI32(minesTextureTile, 0, 2),
  tilePIXI32(minesTextureTile, 0, 1)
];

function setSpriteOwner (sprite, owner) {
  sprite.position.x = -4;
  if (owner === "-") {
    sprite.setTexture(mineTextures[0]);
    sprite.position.y = 0;
  }
  else {
    sprite.setTexture(mineTextures[parseInt(owner, 10)]);
    sprite.position.y = -8;
  }
}

function Mine (owner) {
  PIXI.DisplayObjectContainer.call(this);
  this.previousSprite = new PIXI.Sprite(mineTextures[0]);
  this.currentSprite = new PIXI.Sprite(mineTextures[0]);
  this.goblin = new PIXI.Sprite(goblinTexture);
  this.goblin.position.x = -4;
  this.goblin.position.y = -8;
  setSpriteOwner(this.currentSprite, owner);
  this.addChild(this.previousSprite);
  this.addChild(this.currentSprite);
  this.addChild(this.goblin);
  this.updateOwner(owner);
}
Mine.prototype = Object.create(PIXI.DisplayObjectContainer.prototype);
Mine.prototype.constructor = Mine;

Mine.prototype.updateOwner = function (owner, interpolationTime) {
  // TODO : improve that with meta ?
  if (owner === this.currentOwner) return;
  this.previousOwner = this.currentOwner;
  this.currentOwner = owner;
  this.updatedTime = Date.now();
  this.interpolationTime = this.previousOwner && interpolationTime;

  setSpriteOwner(this.currentSprite, this.currentOwner);
  setSpriteOwner(this.previousSprite, this.previousOwner);
  if (!this.interpolationTime) {
    this.previousSprite.alpha = 0;
    this.currentSprite.alpha = 1;
  }
  this.goblin.alpha = (this.currentOwner === "-" ? 1 : 0);
};

Mine.prototype.render = function () {
  if (!this.interpolationTime) return;
  var p = smoothstep(0, this.interpolationTime, Date.now()-this.updatedTime);
  this.previousSprite.alpha = 1-p;
  this.currentSprite.alpha = p;
};

module.exports = Mine;
<|endoftext|>