<commit_before>/** -*- compile-command: "jslint-cli SwitchManipulator.js" -*-
 * Authors:
 *  Cedric Pinson <cedric.pinson@plopbyte.com>
 */

/**
 *  OrbitManipulator
 *  @class
 */
osgGA.SwitchManipulator = function () {
    osgGA.Manipulator.call(this);
    this._manipulatorList = [];
    this._currentManipulator = undefined;
};

/** @lends osgGA.OrbitManipulator.prototype */
osgGA.SwitchManipulator.prototype = osg.objectInehrit(osgGA.Manipulator.prototype, {
    update: function(nv) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.update(nv);
        }
    },
    setNode: function (node) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator.setNode === undefined) {
            osg.log("manipulator has not setNode method");
            return;
        }
        manipulator.setNode(node);
    },
    getNumManipulator: function () {
        return this._manipulatorList.length;
    },
    addManipulator: function (manipulator) {
        this._manipulatorList.push(manipulator);
        if (this._currentManipulator === undefined) {
            this._currentManipulator = 0;
        }
    },
    getManipulatorList: function () {
        return this._manipulatorList;
    },
    setManipulatorIndex: function (index) {
        this._currentManipulator = index;
    },
    getCurrentManipulatorIndex: function() {
        return this._currentManipulator;
    },
    getCurrentManipulator: function () {
        var manipulator = this._manipulatorList[this._currentManipulator];
        return manipulator;
    },
    reset: function() {
        this.getCurrentManipulator().reset();
    },
    computeHomePosition: function() {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            manipulator.computeHomePosition();
        }
    },
    /**
       Method called when a keydown event is triggered
        @type KeyEvent
     */
    keydown: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.keydown(ev);
        }
    },
    /**
       Method called when a keyup event is triggered
       @type KeyEvent
     */
    keyup: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.keyup(ev);
        }
    },
    mouseup: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mouseup(ev);
        }
    },
    mousedown: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousedown(ev);
        }
    },
    mousemove: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousemove(ev);
        }
    },
    dblclick: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.dblclick(ev);
        }
    },
    touchstart: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchstart(ev);
        }
    },
    touchend: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchend(ev);
        }
    },
    touchmove: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchmove(ev);
        }
    },

    touchleave: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchleave(event);
        }
    },
    touchcancel: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchcancel(event);
        }
    },

    gesturestart: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gesturestart(event);
        }
    },
    gestureend: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gestureend(event);
        }
    },
    gesturechange: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gesturechange(event);
        }
    },

    mousewheel: function(ev, intDelta, deltaX, deltaY) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousewheel(ev, intDelta, deltaX, deltaY);
        }
    },
    gamepadaxes: function(axes) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gamepadaxes(axes);
        }
    },
    gamepadbuttondown: function(event, pressed) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gamepadbuttondown(event, pressed);
        }
    },
    getInverseMatrix: function () {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.getInverseMatrix();
        }
    }
});

<commit_msg>Index setter refactor.<commit_after>/** -*- compile-command: "jslint-cli SwitchManipulator.js" -*-
 * Authors:
 *  Cedric Pinson <cedric.pinson@plopbyte.com>
 */

/**
 *  OrbitManipulator
 *  @class
 */
osgGA.SwitchManipulator = function () {
    osgGA.Manipulator.call(this);
    this._manipulatorList = [];
    this._currentManipulator = undefined;
};

/** @lends osgGA.OrbitManipulator.prototype */
osgGA.SwitchManipulator.prototype = osg.objectInehrit(osgGA.Manipulator.prototype, {
    update: function(nv) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.update(nv);
        }
    },
    setNode: function (node) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator.setNode === undefined) {
            osg.log("manipulator has not setNode method");
            return;
        }
        manipulator.setNode(node);
    },
    getNumManipulator: function () {
        return this._manipulatorList.length;
    },
    addManipulator: function (manipulator) {
        this._manipulatorList.push(manipulator);
        if (this._currentManipulator === undefined) {
            this.setManipulatorIndex(0);
        }
    },
    getManipulatorList: function () {
        return this._manipulatorList;
    },
    setManipulatorIndex: function (index) {
        this._currentManipulator = index;
    },
    getCurrentManipulatorIndex: function() {
        return this._currentManipulator;
    },
    getCurrentManipulator: function () {
        var manipulator = this._manipulatorList[this._currentManipulator];
        return manipulator;
    },
    reset: function() {
        this.getCurrentManipulator().reset();
    },
    computeHomePosition: function() {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            manipulator.computeHomePosition();
        }
    },
    /**
       Method called when a keydown event is triggered
        @type KeyEvent
     */
    keydown: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.keydown(ev);
        }
    },
    /**
       Method called when a keyup event is triggered
       @type KeyEvent
     */
    keyup: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.keyup(ev);
        }
    },
    mouseup: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mouseup(ev);
        }
    },
    mousedown: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousedown(ev);
        }
    },
    mousemove: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousemove(ev);
        }
    },
    dblclick: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.dblclick(ev);
        }
    },
    touchstart: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchstart(ev);
        }
    },
    touchend: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchend(ev);
        }
    },
    touchmove: function(ev) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchmove(ev);
        }
    },

    touchleave: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchleave(event);
        }
    },
    touchcancel: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.touchcancel(event);
        }
    },

    gesturestart: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gesturestart(event);
        }
    },
    gestureend: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gestureend(event);
        }
    },
    gesturechange: function(event) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gesturechange(event);
        }
    },

    mousewheel: function(ev, intDelta, deltaX, deltaY) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.mousewheel(ev, intDelta, deltaX, deltaY);
        }
    },
    gamepadaxes: function(axes) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gamepadaxes(axes);
        }
    },
    gamepadbuttondown: function(event, pressed) {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.gamepadbuttondown(event, pressed);
        }
    },
    getInverseMatrix: function () {
        var manipulator = this.getCurrentManipulator();
        if (manipulator !== undefined) {
            return manipulator.getInverseMatrix();
        }
    }
});

<|endoftext|>


<commit_before>'use strict'

// Import main modules
const crypto = require('crypto')
const express = require('express')
const morgan = require('morgan')
const session = require('express-session')
const RedisStore = require('connect-redis')(session)
const passport = require('passport')
const dgram = require('dgram')

// Local modules
const auth = require('./controllers/authentication')
const users = require('./models/users')
const localAuth = require('./controllers/local-auth')
const registryModel = require('./models/service-registry')
const registryController = require('./controllers/service')

const PORT = process.env.PORT || 3000
const API_ROOT = '/api/v1'
const REGISTRY_PORT = process.env.REGISTRY_PORT || 8888

// Immediately begin connecting to redis
const rc = users.initializeRedis({
  // REDIS_NAME is automatically set by docker
  // If not found, assume it's running on the localhost
  host: process.env.REDIS_HOST || '127.0.0.1',
  port: process.env.REDIS_PORT || 6379
})

// Set registry to use our default redis store
registryModel.setStore(rc)

// create the express application
var app = express()

// Setup middleware chain in one place to avoid confusion
// request logging
app.use(morgan(process.env.LOG_FORMAT || 'dev'))
// parse both json and url-encoded body content
// app.use(bodyParser.json())
// app.use(bodyParser.urlencoded({extended: false}))
// support user sessions
app.use(session({
  secret: crypto.randomBytes(64).toString('hex'),
  resave: false,
  saveUninitialized: false,
  store: new RedisStore({client: rc})
}))

// configure passport for user authentication
passport.serializeUser(auth.serializeUser)
passport.deserializeUser(auth.deserializeUser)

// Sets up passport to use Google for authentication
passport.use(localAuth.Strategy())

app.use(passport.initialize())
app.use(passport.session())
app.use(localAuth.GoogleRouter())

// In order to use the main API they must be authenticated
app.use(API_ROOT, auth.ensureAuth('/signin/google'))
app.use(API_ROOT, registryController.Router())

const server = app.listen(PORT, () => {
  const addr = server.address()
  if (addr.address === '::') {
    addr.address = 'localhost'
  }
  console.log(`server listening at http://${addr.address}:${addr.port}`)
})

// Startup UDP Registration server
const registry = dgram.createSocket('udp4')

registry.on('error', (err) => {
  console.log(`Registry error:\n${err.stack}`)
  registry.close()
})

registry.on('message', registryController.registryHandler)

registry.on('listening', () => {
  var address = registry.address()
  console.log(`Registry listening ${address.address}:${address.port}`)
})

registry.bind(REGISTRY_PORT)
<commit_msg>Modified startup to connect to db<commit_after>'use strict'

// Import main modules
const crypto = require('crypto')
const express = require('express')
const morgan = require('morgan')
const session = require('express-session')
const RedisStore = require('connect-redis')(session)
const redis = require('redis')
const passport = require('passport')
const dgram = require('dgram')

// Local modules
const auth = require('./controllers/authentication')
const users = require('./models/users')
const localAuth = require('./controllers/local-auth')
const registryModel = require('./models/service-registry')
const registryController = require('./controllers/service')

const PORT = process.env.PORT || 3000
const API_ROOT = '/api/v1'
const REGISTRY_PORT = process.env.REGISTRY_PORT || 8888

// Immediately begin connecting to redis
const rc = redis.createClient({
  host: process.env.REDIS_HOST || '127.0.0.1',
  port: process.env.REDIS_PORT || 6379
})

// Set registry to use our default redis store
registryModel.setStore(rc)

// Attempt to connect to the users database
users.init().then(() => {
  // create the express application
  var app = express()

  // Setup middleware chain in one place to avoid confusion
  // request logging
  app.use(morgan(process.env.LOG_FORMAT || 'dev'))
  // parse both json and url-encoded body content
  // app.use(bodyParser.json())
  // app.use(bodyParser.urlencoded({extended: false}))
  // support user sessions
  app.use(session({
    secret: crypto.randomBytes(64).toString('hex'),
    resave: false,
    saveUninitialized: false,
    store: new RedisStore({client: rc})
  }))

  // configure passport for user authentication
  passport.serializeUser(auth.serializeUser)
  passport.deserializeUser(auth.deserializeUser)

  // Sets up passport to use Google for authentication
  passport.use(localAuth.Strategy())

  app.use(passport.initialize())
  app.use(passport.session())
  app.use(localAuth.GoogleRouter())

  // In order to use the main API they must be authenticated
  app.use(API_ROOT, auth.ensureAuth('/signin/google'))
  app.use(API_ROOT, registryController.Router())

  const server = app.listen(PORT, () => {
    const addr = server.address()
    if (addr.address === '::') {
      addr.address = 'localhost'
    }
    console.log(`server listening at http://${addr.address}:${addr.port}`)
  })

  // Startup UDP Registration server
  const registry = dgram.createSocket('udp4')

  registry.on('error', (err) => {
    console.log(`Registry error:\n${err.stack}`)
    registry.close()
  })

  registry.on('message', registryController.registryHandler)

  registry.on('listening', () => {
    var address = registry.address()
    console.log(`Registry listening ${address.address}:${address.port}`)
  })

  registry.bind(REGISTRY_PORT)
})
<|endoftext|>


<commit_before>import * as utilities from './utilities';
import * as extractors from './featureExtractors';
import {fft, ifft} from 'fftjs';
import {MeydaAnalyzer} from './meyda-wa';

var Meyda = {
  audioContext: null,
  spn: null,
  bufferSize: 512,
  sampleRate: 44100,
  melBands: 26,
  chromaBands: 12,
  callback: null,
  windowingFunction: 'hanning',
  featureExtractors: extractors,
  EXTRACTION_STARTED: false,
  numberOfMFCCCoefficients: 13,
  _featuresToExtract: [],
  windowing: utilities.applyWindow,
  _errors: {
    notPow2: new Error(
        'Meyda: Buffer size must be a power of 2, e.g. 64 or 512'),
    featureUndef: new Error('Meyda: No features defined.'),
    invalidFeatureFmt: new Error('Meyda: Invalid feature format'),
    invalidInput: new Error('Meyda: Invalid input.'),
    noAC: new Error('Meyda: No AudioContext specified.'),
    noSource: new Error('Meyda: No source node specified.'),
  },

  createMeydaAnalyzer: function (options) {
    return new MeydaAnalyzer(options, Meyda);
  },

  extract: function (feature, signal, previousSignal) {
    if (!signal)
        throw this._errors.invalidInput;
    else if (typeof signal != 'object')
        throw this._errors.invalidInput;
    else if (!feature)
        throw this._errors.featureUndef;
    else if (!utilities.isPowerOfTwo(signal.length))
        throw this._errors.notPow2;

    if (typeof this.barkScale == 'undefined' ||
            this.barkScale.length != this.bufferSize) {
      this.barkScale = utilities.createBarkScale(
          this.bufferSize,
          this.sampleRate,
          this.bufferSize
      );
    }

    // Recalculate mel bank if buffer length changed
    if (typeof this.melFilterBank == 'undefined' ||
            this.barkScale.length != this.bufferSize ||
            this.melFilterBank.length != this.melBands) {
      this.melFilterBank = utilities.createMelFilterBank(
          Math.max(this.melBands, this.numberOfMFCCCoefficients),
          this.sampleRate,
          this.bufferSize);
    }

    // Recalculate chroma bank if buffer length changed
    if (typeof this.chromaFilterBank == 'undefined' ||
            this.chromaFilterBank.length != this.chromaBands) {
      this.chromaFilterBank = utilities.createChromaFilterBank(
          this.chromaBands,
          this.sampleRate,
          this.bufferSize);
    }

    if (typeof signal.buffer == 'undefined') {
      //signal is a normal array, convert to F32A
      this.signal = utilities.arrayToTyped(signal);
    } else {
      this.signal = signal;
    }

    let preparedSignal = prepareSignalWithSpectrum(
            signal,
            this.windowingFunction,
            this.bufferSize);

    this.signal = preparedSignal.windowedSignal;
    this.complexSpectrum = preparedSignal.complexSpectrum;
    this.ampSpectrum = preparedSignal.ampSpectrum;

    if (previousSignal) {
      let preparedSignal = prepareSignalWithSpectrum(previousSignal,
              this.windowingFunction,
              this.bufferSize);

      this.previousSignal = preparedSignal.windowedSignal;
      this.previousComplexSpectrum = preparedSignal.complexSpectrum;
      this.previousAmpSpectrum = preparedSignal.ampSpectrum;
    }

    const extract = (feature) => {
      return this.featureExtractors[feature]({
        ampSpectrum:this.ampSpectrum,
        chromaFilterBank: this.chromaFilterBank,
        complexSpectrum:this.complexSpectrum,
        signal:this.signal,
        bufferSize:this.bufferSize,
        sampleRate:this.sampleRate,
        barkScale:this.barkScale,
        melFilterBank:this.melFilterBank,
        previousSignal:this.previousSignal,
        previousAmpSpectrum:this.previousAmpSpectrum,
        previousComplexSpectrum:this.previousComplexSpectrum,
        numberOfMFCCCoefficients:this.numberOfMFCCCoefficients,
      });
    };

    if (typeof feature === 'object') {
      feature.reduce((acc, el) =>
        Object.assign({}, acc, {
          [el]: extract(el),
        }), {});
    } else if (typeof feature === 'string') {
      return extract(feature);
    } else {
      throw this._errors.invalidFeatureFmt;
    }
  },
};

var prepareSignalWithSpectrum = function (signal,
  windowingFunction,
  bufferSize) {
  var preparedSignal = {};

  if (typeof signal.buffer == 'undefined') {
    //signal is a normal array, convert to F32A
    preparedSignal.signal = utilities.arrayToTyped(signal);
  }  else {
    preparedSignal.signal = signal;
  }

  preparedSignal.windowedSignal = utilities.applyWindow(
    preparedSignal.signal,
    windowingFunction);

  preparedSignal.complexSpectrum = fft(preparedSignal.windowedSignal);
  preparedSignal.ampSpectrum = new Float32Array(bufferSize / 2);
  for (var i = 0; i < bufferSize / 2; i++) {
    preparedSignal.ampSpectrum[i] = Math.sqrt(
      Math.pow(preparedSignal.complexSpectrum.real[i], 2) +
      Math.pow(preparedSignal.complexSpectrum.imag[i], 2));
  }

  return preparedSignal;
};

export default Meyda;

if (typeof window !== 'undefined') window.Meyda = Meyda;
<commit_msg>Update main.js<commit_after>import * as utilities from './utilities';
import * as extractors from './featureExtractors';
import {fft, ifft} from 'fftjs';
import {MeydaAnalyzer} from './meyda-wa';

var Meyda = {
  audioContext: null,
  spn: null,
  bufferSize: 512,
  sampleRate: 44100,
  melBands: 26,
  chromaBands: 12,
  callback: null,
  windowingFunction: 'hanning',
  featureExtractors: extractors,
  EXTRACTION_STARTED: false,
  numberOfMFCCCoefficients: 13,
  _featuresToExtract: [],
  windowing: utilities.applyWindow,
  _errors: {
    notPow2: new Error(
        'Meyda: Buffer size must be a power of 2, e.g. 64 or 512'),
    featureUndef: new Error('Meyda: No features defined.'),
    invalidFeatureFmt: new Error('Meyda: Invalid feature format'),
    invalidInput: new Error('Meyda: Invalid input.'),
    noAC: new Error('Meyda: No AudioContext specified.'),
    noSource: new Error('Meyda: No source node specified.'),
  },

  createMeydaAnalyzer: function (options) {
    return new MeydaAnalyzer(options, Meyda);
  },

  extract: function (feature, signal, previousSignal) {
    if (!signal)
        throw this._errors.invalidInput;
    else if (typeof signal != 'object')
        throw this._errors.invalidInput;
    else if (!feature)
        throw this._errors.featureUndef;
    else if (!utilities.isPowerOfTwo(signal.length))
        throw this._errors.notPow2;

    if (typeof this.barkScale == 'undefined' ||
            this.barkScale.length != this.bufferSize) {
      this.barkScale = utilities.createBarkScale(
          this.bufferSize,
          this.sampleRate,
          this.bufferSize
      );
    }

    // Recalculate mel bank if buffer length changed
    if (typeof this.melFilterBank == 'undefined' ||
            this.barkScale.length != this.bufferSize ||
            this.melFilterBank.length != this.melBands) {
      this.melFilterBank = utilities.createMelFilterBank(
          Math.max(this.melBands, this.numberOfMFCCCoefficients),
          this.sampleRate,
          this.bufferSize);
    }

    // Recalculate chroma bank if buffer length changed
    if (typeof this.chromaFilterBank == 'undefined' ||
            this.chromaFilterBank.length != this.chromaBands) {
      this.chromaFilterBank = utilities.createChromaFilterBank(
          this.chromaBands,
          this.sampleRate,
          this.bufferSize);
    }

    if (typeof signal.buffer == 'undefined') {
      //signal is a normal array, convert to F32A
      this.signal = utilities.arrayToTyped(signal);
    } else {
      this.signal = signal;
    }

    let preparedSignal = prepareSignalWithSpectrum(
            signal,
            this.windowingFunction,
            this.bufferSize);

    this.signal = preparedSignal.windowedSignal;
    this.complexSpectrum = preparedSignal.complexSpectrum;
    this.ampSpectrum = preparedSignal.ampSpectrum;

    if (previousSignal) {
      let preparedSignal = prepareSignalWithSpectrum(previousSignal,
              this.windowingFunction,
              this.bufferSize);

      this.previousSignal = preparedSignal.windowedSignal;
      this.previousComplexSpectrum = preparedSignal.complexSpectrum;
      this.previousAmpSpectrum = preparedSignal.ampSpectrum;
    }

    const extract = (feature) => {
      return this.featureExtractors[feature]({
        ampSpectrum:this.ampSpectrum,
        chromaFilterBank: this.chromaFilterBank,
        complexSpectrum:this.complexSpectrum,
        signal:this.signal,
        bufferSize:this.bufferSize,
        sampleRate:this.sampleRate,
        barkScale:this.barkScale,
        melFilterBank:this.melFilterBank,
        previousSignal:this.previousSignal,
        previousAmpSpectrum:this.previousAmpSpectrum,
        previousComplexSpectrum:this.previousComplexSpectrum,
        numberOfMFCCCoefficients:this.numberOfMFCCCoefficients,
      });
    };

    if (typeof feature === 'object') {
      return feature.reduce((acc, el) =>
        Object.assign({}, acc, {
          [el]: extract(el),
        }), {});
    } else if (typeof feature === 'string') {
      return extract(feature);
    } else {
      throw this._errors.invalidFeatureFmt;
    }
  },
};

var prepareSignalWithSpectrum = function (signal,
  windowingFunction,
  bufferSize) {
  var preparedSignal = {};

  if (typeof signal.buffer == 'undefined') {
    //signal is a normal array, convert to F32A
    preparedSignal.signal = utilities.arrayToTyped(signal);
  }  else {
    preparedSignal.signal = signal;
  }

  preparedSignal.windowedSignal = utilities.applyWindow(
    preparedSignal.signal,
    windowingFunction);

  preparedSignal.complexSpectrum = fft(preparedSignal.windowedSignal);
  preparedSignal.ampSpectrum = new Float32Array(bufferSize / 2);
  for (var i = 0; i < bufferSize / 2; i++) {
    preparedSignal.ampSpectrum[i] = Math.sqrt(
      Math.pow(preparedSignal.complexSpectrum.real[i], 2) +
      Math.pow(preparedSignal.complexSpectrum.imag[i], 2));
  }

  return preparedSignal;
};

export default Meyda;

if (typeof window !== 'undefined') window.Meyda = Meyda;
<|endoftext|>


<commit_before>// Copyright 2020, University of Colorado Boulder

/**
 * Runs tasks for pre-commit, including lint and qunit testing.  Avoids the overhead of grunt and Gruntfile.js for speed
 *
 * USAGE:
 * cd ${repo}
 * node ../perennial/js/scripts/hook-pre-commit.js
 *
 * OPTIONS:
 * --console: outputs information to the console for debugging
 *
 * See also phet-info/git-template-dir/hooks/pre-commit for how this is used in precommit hooks.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

// Require statements which should be generally available via node or perennial
const fs = require( 'fs' );
const path = require( 'path' );
const _ = require( 'lodash' ); // eslint-disable-line
const puppeteer = require( 'puppeteer' );
const withServer = require( '../common/withServer' );
const execute = require( '../common/execute' );

( async () => {

// Identify the current repo
  const repo = process.cwd().split( path.sep ).pop();

// Console logging via --console
  const commandLineArguments = process.argv.slice( 2 );
  const outputToConsole = commandLineArguments.includes( '--console' );

// Run lint tests if they exist in the checked-out SHAs.
  try {
    const lint = require( '../../../chipper/js/grunt/lint' );
    if ( lint.chipperAPIVersion === 'promises1' ) {

      // lint() automatically filters out non-lintable repos
      const results = await lint( [ `../${repo}` ], {
        cache: true
      } );

      const problems = results.filter( result => result.errorCount > 0 || result.warningCount > 0 );
      problems.forEach( result => console.error( `lint failed in ${repo}`, result.filePath, result.messages.map( m => JSON.stringify( m, null, 2 ) ).join( '\n' ) ) );
      if ( problems.length > 0 ) {
        process.exit( 1 );
      }

      outputToConsole && console.log( `Linting passed with results.length: ${results.length}` );
    }
    else {
      console.log( 'chipper/js/grunt/lint not compatible' );
    }
  }
  catch( e ) {
    console.log( 'chipper/js/grunt/lint not found' );
  }

// These sims don't have package.json or media that requires checking.
  const optOutOfReportMedia = [
    'decaf',
    'phet-android-app',
    'babel',
    'phet-info',
    'phet-ios-app',
    'sherpa',
    'smithers',
    'tasks',
    'weddell'
  ];

// Make sure license.json for images/audio is up-to-date
  if ( !optOutOfReportMedia.includes( repo ) ) {
    try {
      const reportMedia = require( '../../../chipper/js/grunt/reportMedia' );

      const success = await reportMedia( repo );

      // At the moment reportMedia uses grunt.fail, but we defensively use the return value here in case that changes.
      if ( !success ) {
        process.exit( 1 );
      }
    }
    catch( e ) {
      console.log( 'chipper/js/grunt/reportMedia not found' );
    }
  }

  // Run typescript type checker if it exists in the checked-out shas
  if ( fs.existsSync( '../chipper/tsconfig/all/tsconfig.json' ) ) {
    try {

      const results = await execute( 'node', [ '../../../chipper/node_modules/typescript/bin/tsc' ], '../chipper/tsconfig/all', {
        errors: 'resolve'
      } );

      if ( results.code === 0 ) {
        outputToConsole && console.log( 'tsc passed' );
      }
      else {
        console.log( results );
        process.exit( results.code );
      }
    }
    catch( e ) {
      console.log( 'chipper/js/grunt/tsc not found' );
    }
  }
  else {
    outputToConsole && console.log( 'tsconfig.json not found, skipping tsc' );
  }

// Run qunit tests if puppeteerQUnit exists in the checked-out SHAs and a test HTML exists.
  try {
    const puppeteerQUnit = require( '../../../aqua/js/local/puppeteerQUnit' );
    if ( repo !== 'scenery' && repo !== 'phet-io-wrappers' ) { // scenery unit tests take too long, so skip those
      const testFilePath = `${repo}/${repo}-tests.html`;
      const exists = fs.existsSync( `../${testFilePath}` );
      if ( exists ) {
        const browser = await puppeteer.launch();

        const result = await withServer( async port => {
          return puppeteerQUnit( browser, `http://localhost:${port}/${testFilePath}?ea&brand=phet-io` );
        } );

        await browser.close();

        outputToConsole && console.log( `${repo}: ${JSON.stringify( result, null, 2 )}` );
        if ( !result.ok ) {
          console.error( `unit tests failed in ${repo}`, result );
          process.exit( 1 ); // fail as soon as there is one problem
        }
      }

      outputToConsole && console.log( 'QUnit: no problems detected' );
    }
  }
  catch( e ) {
    console.log( e );
  }
} )();<commit_msg>support linting again from pre-commit hooks, https://github.com/phetsims/chipper/issues/1286<commit_after>// Copyright 2020, University of Colorado Boulder

/**
 * Runs tasks for pre-commit, including lint and qunit testing.  Avoids the overhead of grunt and Gruntfile.js for speed
 *
 * USAGE:
 * cd ${repo}
 * node ../perennial/js/scripts/hook-pre-commit.js
 *
 * OPTIONS:
 * --console: outputs information to the console for debugging
 *
 * See also phet-info/git-template-dir/hooks/pre-commit for how this is used in precommit hooks.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 */

// Require statements which should be generally available via node or perennial
const fs = require( 'fs' );
const path = require( 'path' );
const _ = require( 'lodash' ); // eslint-disable-line
const puppeteer = require( 'puppeteer' );
const withServer = require( '../common/withServer' );
const execute = require( '../common/execute' );
const child_process = require( 'child_process' );

( async () => {

// Identify the current repo
  const repo = process.cwd().split( path.sep ).pop();

// Console logging via --console
  const commandLineArguments = process.argv.slice( 2 );
  const outputToConsole = commandLineArguments.includes( '--console' );

// Run lint tests if they exist in the checked-out SHAs.
  try {
    const lint = require( '../../../perennial-alias/js/grunt/lint' );

    // Run lint tests if they exist in the checked-out SHAs.
    if ( lint.APIVersion === 'promisesPerRepo1' ) {

      // Run from perennial-alias to preserve the cache
      const resultsText = child_process.execSync( `node js/grunt/lint.js --lintFromCommandLine --repos=${repo}`, {
        cwd: '../perennial-alias'
      } ).toString();

      const results = JSON.parse( resultsText );
      const problems = results.filter( result => result.errorCount > 0 || result.warningCount > 0 );
      if ( problems.length > 0 ) {
        console.log( `lint failed in ${repo}`, '\n', await lint.formatResults( results ) );
        process.exit( 1 );
      }

      outputToConsole && console.log( `Linting passed with results.length: ${results.length}` );
    }
    else {
      console.log( 'chipper/js/grunt/lint not compatible' );
    }
  }
  catch( e ) {
    console.log( 'chipper/js/grunt/lint not found', e );
  }

// These sims don't have package.json or media that requires checking.
  const optOutOfReportMedia = [
    'decaf',
    'phet-android-app',
    'babel',
    'phet-info',
    'phet-ios-app',
    'sherpa',
    'smithers',
    'tasks',
    'weddell'
  ];

// Make sure license.json for images/audio is up-to-date
  if ( !optOutOfReportMedia.includes( repo ) ) {
    try {
      const reportMedia = require( '../../../chipper/js/grunt/reportMedia' );

      const success = await reportMedia( repo );

      // At the moment reportMedia uses grunt.fail, but we defensively use the return value here in case that changes.
      if ( !success ) {
        process.exit( 1 );
      }
    }
    catch( e ) {
      console.log( 'chipper/js/grunt/reportMedia not found' );
    }
  }

  // Run typescript type checker if it exists in the checked-out shas
  if ( fs.existsSync( '../chipper/tsconfig/all/tsconfig.json' ) ) {
    try {

      const results = await execute( 'node', [ '../../../chipper/node_modules/typescript/bin/tsc' ], '../chipper/tsconfig/all', {
        errors: 'resolve'
      } );

      if ( results.code === 0 ) {
        outputToConsole && console.log( 'tsc passed' );
      }
      else {
        console.log( results );
        process.exit( results.code );
      }
    }
    catch( e ) {
      console.log( 'chipper/js/grunt/tsc not found' );
    }
  }
  else {
    outputToConsole && console.log( 'tsconfig.json not found, skipping tsc' );
  }

// Run qunit tests if puppeteerQUnit exists in the checked-out SHAs and a test HTML exists.
  try {
    const puppeteerQUnit = require( '../../../aqua/js/local/puppeteerQUnit' );
    if ( repo !== 'scenery' && repo !== 'phet-io-wrappers' ) { // scenery unit tests take too long, so skip those
      const testFilePath = `${repo}/${repo}-tests.html`;
      const exists = fs.existsSync( `../${testFilePath}` );
      if ( exists ) {
        const browser = await puppeteer.launch();

        const result = await withServer( async port => {
          return puppeteerQUnit( browser, `http://localhost:${port}/${testFilePath}?ea&brand=phet-io` );
        } );

        await browser.close();

        outputToConsole && console.log( `${repo}: ${JSON.stringify( result, null, 2 )}` );
        if ( !result.ok ) {
          console.error( `unit tests failed in ${repo}`, result );
          process.exit( 1 ); // fail as soon as there is one problem
        }
      }

      outputToConsole && console.log( 'QUnit: no problems detected' );
    }
  }
  catch( e ) {
    console.log( e );
  }
} )();<|endoftext|>


<commit_before>#!/usr/bin/env node
"use strict";

const fs = require("fs");

const chalk = require("chalk");
const shell = require("shelljs");

//Max number of commiters and file-types to show; for now 10 (NOTE: this can be changed)
let maxCommitersToShow = 10;
let maxFileTypesToShow = 10;

//Shell commands
let repoNameCmd = "basename `git rev-parse --show-toplevel`";
let firstCommitCmd = "git log --reverse --format='format:%ci' | head -1 | awk '{ print $1 }'";
let authorsCommitsCmd = "git shortlog -s -n --all | awk '{ print $0\"|;:\"}'";
let branchesNameCmd = "git branch -r | awk '{ print $0\"|;:\"}' | grep -v \"\\->\"";
let fileTypesCmd = "find . -type f -name '*.*' | sed 's/.*\\.//' | sort | uniq -c | sort -r | grep -v \"~\" | awk '{ print $0\",\"}'";

//Holds the git data for this repo
let gitRepoData = {
  repoName: "",
  firstCommit: "",
  mainAuthorName: "",
  authorsContributions: [],
  languagesStatistics: [],
  numBranches: "",
  fileTypes: [],
  commitLogs: []
};

/**
 * @brief Executes shell command
 *
 * @param commandToExec The command to execute
 *
 * @return Returns the stdout output of the shell command
 */
function execShellCommand(commandToExec) {
  return shell.exec(commandToExec, {silent: true}).stdout.replace(/^\s+|\s+$/g, '') || "N/A";
}

/**
 * @brief Displayes git statistics
 */
function displayGitStats() {
  //TODO: pretty print this
  console.log(`Repo: ${gitRepoData.repoName}`);
  console.log(`First-commit: ${gitRepoData.firstCommit}`);

  let noOfCommiters = gitRepoData.authorsContributions.length;
  let noOfCommitersToShow = noOfCommiters > maxCommitersToShow ? maxCommitersToShow : noOfCommiters;
  for(let i = 0; i < noOfCommitersToShow; i++) {
    console.log(`#Commits: ${gitRepoData.authorsContributions[i].noOfCommits}, ${gitRepoData.authorsContributions[i].name}`);
  }

  //Main author
  console.log(`Lead author: #Commits: ${gitRepoData.authorsContributions[0].noOfCommits}, ${gitRepoData.authorsContributions[0].name}`);

  //Branches info
  console.log(`Number of branches: ${gitRepoData.numBranches}`);

  //Filetypes
  console.log(`Total # of file types: ${gitRepoData.fileTypes.length}`);
  console.log("Filetypes:");
  let noOfFileTypes = gitRepoData.fileTypes.length;
  let noOfFileTypesToShow = noOfFileTypes > maxFileTypesToShow ? maxFileTypesToShow : noOfFileTypes;
  for(let i = 0; i < noOfFileTypesToShow; i++) {
    process.stdout.write(`${gitRepoData.fileTypes[i]}, `);
  }
  console.log();

}

/**
 * @brief Get all the Git data and process it to
 *  generate displayable info
 */
function getAndProcessGitData() {
  //Name of the Repository
  gitRepoData.repoName = execShellCommand(repoNameCmd);

  //First commit date
  gitRepoData.firstCommit = execShellCommand(firstCommitCmd);

  //Get Authors Contributions; NOTE: loop is iterated till length-1 since the last item is empty
  let authorsCommits = execShellCommand(authorsCommitsCmd).split("|;:");
  for(let i = 0; i < authorsCommits.length - 1; i++) {
    let [ noOfCommits, name ] = authorsCommits[i].replace(/^\s+|\s+$/g, '').split("\t");
    gitRepoData.authorsContributions.push({ "noOfCommits": noOfCommits, "name": name });
  }

  //Get number of branches; NOTE: 1 is subtracted as the last item is empty
  let branchesName = execShellCommand(branchesNameCmd).split("|;:");
  gitRepoData.numBranches = branchesName.length - 1;

  //Get Filetypes
  let fileTypes = execShellCommand(fileTypesCmd).split(",");
  for(let i = 0; i < fileTypes.length - 1; i++) {
    gitRepoData.fileTypes.push(fileTypes[i].replace(/^\s+|\s+$/g, ''));
  }

  //Get Languages Statistics

  //Get Commit Logs

  //Display the statistics
  displayGitStats();
}

/**
 * @brief Checks for availability of dependencies and
 *   calls @getAndProcessGitData
 */
function main() {
  //Check if this is a git repository or not
  if(!fs.existsSync(".git")) {
    console.log(chalk.red.bold("ERROR: no .git directory present"));
    process.exit(1);
  }

  //Check that git is installed
  if(!shell.which("git")) {
    console.log(chalk.red.bold("ERROR: this script requires git"));
    process.exit(1);
  }

  //Start gathering data for presentation
  getAndProcessGitData();
}

if(require.main === module) {
  main();
}
<commit_msg>Finished all the features Added nice table layout<commit_after>#!/usr/bin/env node
"use strict";

const fs = require("fs");

const chalk = require("chalk");
const shell = require("shelljs");
const Table = require("cli-table");

//Max number of commiters and file-types to show
let maxCommitersToShow = 5;
let maxFileTypesToShow = 10;

//Shell commands
let repoNameCmd = "basename `git rev-parse --show-toplevel`";
let firstCommitCmd = "git log --reverse --format='format:%ci' | head -1 | awk '{ print $1 }'";
let authorsCommitsCmd = "git shortlog -s -n --all | awk '{ print $0\"|;:\"}'";
let branchesNameCmd = "git branch -r | awk '{ print $0\"|;:\"}' | grep -v \"\\->\"";
let fileTypesCmd = "find . -type f -name '*.*' | sed 's/.*\\.//' | sort | uniq -c | sort -r | grep -v \"~\" | awk '{ print $0\",\"}'";
let totalNumberOfCommitsCmd = "git rev-list --all --count";

//Holds the git data for this repo
let gitRepoData = {
  repoName: "",
  firstCommit: "",
  authorsContributions: [],
  numBranches: "",
  fileTypes: [],
  totalNumberOfCommitsAcrossAllBranches: ""
};

/**
 * @brief Executes shell command
 *
 * @param commandToExec The command to execute
 *
 * @return Returns the stdout output of the shell command
 */
function execShellCommand(commandToExec) {
  return shell.exec(commandToExec, {silent: true}).stdout.replace(/^\s+|\s+$/g, '') || "N/A";
}

/**
 * @brief Displayes git statistics
 */
function displayGitStats() {
  const table = new Table();

  //Top commiters
  let noOfCommiters = gitRepoData.authorsContributions.length;
  let noOfCommitersToShow = noOfCommiters > maxCommitersToShow ? maxCommitersToShow : noOfCommiters;
  let topCommiters = "";
  for(let i = 0; i < noOfCommitersToShow; i++) {
    topCommiters += `#Commits: ${gitRepoData.authorsContributions[i].noOfCommits}, ${gitRepoData.authorsContributions[i].name}`;
    if(i < noOfCommitersToShow - 1) {
      topCommiters += `\n`;
    }
  }

  //Filetypes
  let noOfFileTypes = gitRepoData.fileTypes.length;
  let noOfFileTypesToShow = noOfFileTypes > maxFileTypesToShow ? maxFileTypesToShow : noOfFileTypes;
  let topFiletypes = "";
  for(let i = 0; i < noOfFileTypesToShow; i++) {
    topFiletypes += `${gitRepoData.fileTypes[i]}`;
    if(i < noOfFileTypesToShow - 1) {
      topFiletypes += `\n`;
    }
  }

  table.push(
    { 'Repo': gitRepoData.repoName },
    { 'First Commit': gitRepoData.firstCommit },
    { 'Lead Author & #Commits': `${gitRepoData.authorsContributions[0].name} & ${gitRepoData.authorsContributions[0].noOfCommits}` },
    { 'Number of branches': gitRepoData.numBranches },
    { 'Total # of file types': gitRepoData.fileTypes.length },
    { 'Total commits across all branches': gitRepoData.totalNumberOfCommitsAcrossAllBranches },
    { 'Top 5 committers': topCommiters },
    { 'Top 10 file-types': topFiletypes }
  );

  console.log(table.toString());
}

/**
 * @brief Get all the Git data and process it to
 *  generate displayable info
 */
function getAndProcessGitData() {
  //Name of the Repository
  gitRepoData.repoName = execShellCommand(repoNameCmd);

  //First commit date
  gitRepoData.firstCommit = execShellCommand(firstCommitCmd);

  //Get Authors Contributions; NOTE: loop is iterated till length-1 since the last item is empty
  let authorsCommits = execShellCommand(authorsCommitsCmd).split("|;:");
  for(let i = 0; i < authorsCommits.length - 1; i++) {
    let [ noOfCommits, name ] = authorsCommits[i].replace(/^\s+|\s+$/g, '').split("\t");
    gitRepoData.authorsContributions.push({ "noOfCommits": noOfCommits, "name": name });
  }

  //Get number of branches; NOTE: 1 is subtracted as the last item is empty
  let branchesName = execShellCommand(branchesNameCmd).split("|;:");
  gitRepoData.numBranches = branchesName.length - 1;

  //Get Filetypes
  let fileTypes = execShellCommand(fileTypesCmd).split(",");
  for(let i = 0; i < fileTypes.length - 1; i++) {
    gitRepoData.fileTypes.push(fileTypes[i].replace(/^\s+|\s+$/g, ''));
  }

  //To get the commit count across all branches:
  gitRepoData.totalNumberOfCommitsAcrossAllBranches = execShellCommand(totalNumberOfCommitsCmd);

  //Display the statistics
  displayGitStats();
}

/**
 * @brief Checks for availability of dependencies and
 *   calls @getAndProcessGitData
 */
function main() {
  //Check if this is a git repository or not
  if(!fs.existsSync(".git")) {
    console.log(chalk.red.bold("ERROR: no .git directory present"));
    process.exit(1);
  }

  //Check that git is installed
  if(!shell.which("git")) {
    console.log(chalk.red.bold("ERROR: this script requires git"));
    process.exit(1);
  }

  //Start gathering data for presentation
  getAndProcessGitData();
}

if(require.main === module) {
  main();
}
<|endoftext|>


<commit_before>var app = require('app');
var Menu = require('menu');
var Tray = require('tray');
var BrowserWindow = require('browser-window');

var checkForUpdates = function () {};

if (process.platform == 'darwin') {
  // Auto updater for Darwin.
  var autoUpdater = require('auto-updater');
  autoUpdater.on('error', function (event, message) {
    console.log(message);
  });
  autoUpdater.on('checking-for-update', function () {
    console.log('Checking for update');
  });
  autoUpdater.on('update-available', function () {
    console.log('Update available');
  });
  autoUpdater.on('update-not-available', function () {
    console.log('Update not available');
  });
  autoUpdater.on('update-downloaded', function () {
    console.log('Update downloaded');
  });
  autoUpdater.setFeedUrl('https://net-tsinghua.herokuapp.com/update/osx/' +
                         app.getVersion());
  checkForUpdates = function () {
    autoUpdater.checkForUpdates();
  }
} else if (process.platform == 'win32') {
  var squirrelCommand = process.argv[1];
  switch (squirrelCommand) {
    case '--squirrel-install':
      console.log('App installed.');
      app.quit();
      break;
    case '--squirrel-updated':
      console.log('App updated.');

      // Optionally do things such as:
      //
      // - Install desktop and start menu shortcuts
      // - Add your .exe to the PATH
      // - Write to the registry for things like file associations and
      //   explorer context menus

      // Always quit when done
      app.quit();
      break;
    case '--squirrel-uninstall':
      // Undo anything you did in the --squirrel-install and
      // --squirrel-updated handlers

      // Always quit when done
      console.log('Uninstalling.');
      app.quit();
      break;
    case '--squirrel-obsolete':
      // This is called on the outgoing version of your app before
      // we update to the new version - it's the opposite of
      // --squirrel-updated
      console.log('About to update to a newer version.');
      app.quit();
      break;
  }
}

// Load config.
var fs = require('fs');
var config = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf-8"));
var path = require('path');

var net = require('./net');
var usereg = require('./usereg');
var utils = require('./utils')

var status = 'UNKNOWN';
var last_session = {};
var sessions = [];
var last_check = null
var total_usage = null;
var balance = null;

var STATUS_STR = {
  UNKNOWN: '未知状态',
  OFFLINE: '离线',
  ONLINE: '在线',
  OTHERS_ACCOUNT_ONLINE: '他人账号在线',
  ERROR: '网络错误',
  NO_CONNECTION: '无连接'
}

var appIcon = null;

function get_menu_template() {
  var template = [];

  // Status.
  var status_str = STATUS_STR[status];
  // Show session usage if possible.
  if ((status == 'ONLINE' || status == 'OTHERS_ACCOUNT_ONLINE') && last_session)
    status_str = status_str + ' - ' + utils.usage_str(last_session.usage);
  template.push({label: status_str, enabled: false});

  // Account info.
  template.push({type: 'separator'});
  if (!config.username) {
    template.push({label: '未设置帐号', enabled: false});
  } else {
    template.push({label: config.username, enabled: false});
    template.push({label: '本月流量：' + utils.usage_str(total_usage),
                   enabled: false});
    template.push({label: '当前余额：' + utils.balance_str(balance),
                   enabled: false});
  }

  // Sessions.
  template.push({type: 'separator'});
  if (sessions.length == 0) {
    template.push({label: '无设备在线', enabled: false});
  } else {
    template.push({label: '当前在线', enabled: false});
    sessions.forEach(function (session) {
      template.push({label: session.device_name, submenu: [
        {label: session.ip, enabled: false},
        {label: utils.time_passed_str(session.start_time) + '上线',
         enabled: false},
        {label: '≥ ' + utils.usage_str(session.usage), enabled: false},
        {label: '下线'}
      ]});
    });
  }
  template.push({label: '上次更新：' + utils.time_passed_str(last_check),
                 enabled: false});

  return template.concat([
    // Actions.
    {type: 'separator'},
    {label: '上线', click: login},
    {label: '下线', click: logout},
    {label: '现在刷新', click: refresh},

    // Config.
    {type: 'separator'},
    {label: '自动管理', type: 'checkbox', checked: config.auto_manage,
     click: function () { config.auto_manage = !config.auto_manage; }},
    {label: '账号设置...', click: account_setting},

    // About.
    {type: 'separator'},
    {label: '关于 ' + app.getName(), role: 'about'},

    // Quit.
    {type: 'separator'},
    {label: '退出', click: function() { app.quit(); }}
  ]);
}

function login() {
  console.log('Logging in.');

  net.login(config.username, config.md5_pass, function (err) {
    if (!err)
      update_status();
  });
}

function logout() {
  console.log('Logging out.');

  net.logout(function (err) {
    if (!err)
      update_status();
  });
}

// FIXME: This will close the menu if it is already open.
function reset_menu() {
  if (appIcon) {
    console.log('Reseting menu.');
    appIcon.setContextMenu(Menu.buildFromTemplate(get_menu_template()));
  }
}

function update_status(callback) {
  console.log('Updating status.');

  if (typeof callback === 'undefined') {
    callback = function () {};
  }

  net.get_status(function (err, infos) {
    if (err) {
      status = 'ERROR';
    } else {
      if (!infos) {
        status = 'OFFLINE';
      } else {
        if (config.username == infos.username) {
          status = 'ONLINE';

          // These infos belong to current account, save it.
          total_usage = infos.total_usage;
          balance = infos.balance;
        } else {
          status = 'OTHERS_ACCOUNT_ONLINE';
        }
        // Got something useful, update infos.
        last_session.ip = infos.ip;
        last_session.start_time = infos.start_time;
        last_session.usage = infos.usage;
      }
    }
    callback();
    reset_menu();
  });
}

function update_infos(callback) {
  console.log('Updating infos using usereg.');

  if (typeof callback === 'undefined') {
    callback = function () {};
  }

  usereg.get_infos(config.username, config.md5_pass, function (err, infos) {
    if (err) {
      console.error('Failed to update infos using usereg: %s', err);
    } else {
      total_usage = infos.usage;
      balance = infos.balance;
      sessions = infos.sessions;
    }
  })
}

// Apart from updating data, we need to do some actions when status updated.
function refresh_status() {
  update_status(function () {
    // Try to login if needed.
    if (status == 'OFFLINE' && config.auto_manage && config.username)
      login();
  });
}

// Updating data is all we need.
function refresh_infos() {
  update_infos();
}

// Refresh all.
function refresh() {
  refresh_status();
  refresh_infos();
}

// Set clocks.
setInterval(refresh_status, config.status_update_interval_msec);
setInterval(refresh_infos, config.info_update_interval_msec);

// FIXME: Looks ugly now.
function account_setting() {
  var dialog = new BrowserWindow({width: 220, height: 120, resizable: false});
  dialog.loadUrl('file://' + __dirname + '/account_setting.html');
}

app.on('ready', function() {
  appIcon = new Tray(path.join(__dirname, '../resource/icon.png'));

  reset_menu();
  appIcon.setToolTip('This is my application.');

  // Tray balloon, currently only supported in Windows.
  if (!config.username) {
    appIcon.displayBalloon({
      title: '未设置帐号',
      content: '点击这里设置帐号\n或者稍后右键点击状态栏图标 > 账号设置'
    });
  }
  appIcon.on('balloon-clicked', function () {
    account_setting();
  });

  refresh();  // First shot.

  checkForUpdates();
});

app.on('window-all-closed', function() {});
<commit_msg>Fix a bug that sessions will not be shown immediately<commit_after>var app = require('app');
var Menu = require('menu');
var Tray = require('tray');
var BrowserWindow = require('browser-window');

var checkForUpdates = function () {};

if (process.platform == 'darwin') {
  // Auto updater for Darwin.
  var autoUpdater = require('auto-updater');
  autoUpdater.on('error', function (event, message) {
    console.log(message);
  });
  autoUpdater.on('checking-for-update', function () {
    console.log('Checking for update');
  });
  autoUpdater.on('update-available', function () {
    console.log('Update available');
  });
  autoUpdater.on('update-not-available', function () {
    console.log('Update not available');
  });
  autoUpdater.on('update-downloaded', function () {
    console.log('Update downloaded');
  });
  autoUpdater.setFeedUrl('https://net-tsinghua.herokuapp.com/update/osx/' +
                         app.getVersion());
  checkForUpdates = function () {
    autoUpdater.checkForUpdates();
  }
} else if (process.platform == 'win32') {
  var squirrelCommand = process.argv[1];
  switch (squirrelCommand) {
    case '--squirrel-install':
      console.log('App installed.');
      app.quit();
      break;
    case '--squirrel-updated':
      console.log('App updated.');

      // Optionally do things such as:
      //
      // - Install desktop and start menu shortcuts
      // - Add your .exe to the PATH
      // - Write to the registry for things like file associations and
      //   explorer context menus

      // Always quit when done
      app.quit();
      break;
    case '--squirrel-uninstall':
      // Undo anything you did in the --squirrel-install and
      // --squirrel-updated handlers

      // Always quit when done
      console.log('Uninstalling.');
      app.quit();
      break;
    case '--squirrel-obsolete':
      // This is called on the outgoing version of your app before
      // we update to the new version - it's the opposite of
      // --squirrel-updated
      console.log('About to update to a newer version.');
      app.quit();
      break;
  }
}

// Load config.
var fs = require('fs');
var config = JSON.parse(fs.readFileSync(__dirname + "/config.json", "utf-8"));
var path = require('path');

var net = require('./net');
var usereg = require('./usereg');
var utils = require('./utils')

var status = 'UNKNOWN';
var last_session = {};
var sessions = [];
var last_check = null
var total_usage = null;
var balance = null;

var STATUS_STR = {
  UNKNOWN: '未知状态',
  OFFLINE: '离线',
  ONLINE: '在线',
  OTHERS_ACCOUNT_ONLINE: '他人账号在线',
  ERROR: '网络错误',
  NO_CONNECTION: '无连接'
}

var appIcon = null;

function get_menu_template() {
  var template = [];

  // Status.
  var status_str = STATUS_STR[status];
  // Show session usage if possible.
  if ((status == 'ONLINE' || status == 'OTHERS_ACCOUNT_ONLINE') && last_session)
    status_str = status_str + ' - ' + utils.usage_str(last_session.usage);
  template.push({label: status_str, enabled: false});

  // Account info.
  template.push({type: 'separator'});
  if (!config.username) {
    template.push({label: '未设置帐号', enabled: false});
  } else {
    template.push({label: config.username, enabled: false});
    template.push({label: '本月流量：' + utils.usage_str(total_usage),
                   enabled: false});
    template.push({label: '当前余额：' + utils.balance_str(balance),
                   enabled: false});
  }

  // Sessions.
  template.push({type: 'separator'});
  if (sessions.length == 0) {
    template.push({label: '无设备在线', enabled: false});
  } else {
    template.push({label: '当前在线', enabled: false});
    sessions.forEach(function (session) {
      template.push({label: session.device_name, submenu: [
        {label: session.ip, enabled: false},
        {label: utils.time_passed_str(session.start_time) + '上线',
         enabled: false},
        {label: '≥ ' + utils.usage_str(session.usage), enabled: false},
        {label: '下线'}
      ]});
    });
  }
  template.push({label: '上次更新：' + utils.time_passed_str(last_check),
                 enabled: false});

  return template.concat([
    // Actions.
    {type: 'separator'},
    {label: '上线', click: login},
    {label: '下线', click: logout},
    {label: '现在刷新', click: refresh},

    // Config.
    {type: 'separator'},
    {label: '自动管理', type: 'checkbox', checked: config.auto_manage,
     click: function () { config.auto_manage = !config.auto_manage; }},
    {label: '账号设置...', click: account_setting},

    // About.
    {type: 'separator'},
    {label: '关于 ' + app.getName(), role: 'about'},

    // Quit.
    {type: 'separator'},
    {label: '退出', click: function() { app.quit(); }}
  ]);
}

function login() {
  console.log('Logging in.');

  net.login(config.username, config.md5_pass, function (err) {
    if (!err)
      update_status();
  });
}

function logout() {
  console.log('Logging out.');

  net.logout(function (err) {
    if (!err)
      update_status();
  });
}

// FIXME: This will close the menu if it is already open.
function reset_menu() {
  if (appIcon) {
    console.log('Reseting menu.');
    appIcon.setContextMenu(Menu.buildFromTemplate(get_menu_template()));
  }
}

function update_status(callback) {
  console.log('Updating status.');

  if (typeof callback === 'undefined') {
    callback = function () {};
  }

  net.get_status(function (err, infos) {
    if (err) {
      status = 'ERROR';
    } else {
      if (!infos) {
        status = 'OFFLINE';
      } else {
        if (config.username == infos.username) {
          status = 'ONLINE';

          // These infos belong to current account, save it.
          total_usage = infos.total_usage;
          balance = infos.balance;
        } else {
          status = 'OTHERS_ACCOUNT_ONLINE';
        }
        // Got something useful, update infos.
        last_session.ip = infos.ip;
        last_session.start_time = infos.start_time;
        last_session.usage = infos.usage;
      }
    }
    reset_menu();
    callback();
  });
}

function update_infos(callback) {
  console.log('Updating infos using usereg.');

  if (typeof callback === 'undefined') {
    callback = function () {};
  }

  usereg.get_infos(config.username, config.md5_pass, function (err, infos) {
    if (err) {
      console.error('Failed to update infos using usereg: %s', err);
    } else {
      total_usage = infos.usage;
      balance = infos.balance;
      sessions = infos.sessions;
    }
    reset_menu();
    callback();
  });
}

// Apart from updating data, we need to do some actions when status updated.
function refresh_status() {
  update_status(function () {
    // Try to login if needed.
    if (status == 'OFFLINE' && config.auto_manage && config.username)
      login();
  });
}

// Updating data is all we need.
function refresh_infos() {
  update_infos();
}

// Refresh all.
function refresh() {
  refresh_status();
  refresh_infos();
}

// Set clocks.
setInterval(refresh_status, config.status_update_interval_msec);
setInterval(refresh_infos, config.info_update_interval_msec);

// FIXME: Looks ugly now.
function account_setting() {
  var dialog = new BrowserWindow({width: 220, height: 120, resizable: false});
  dialog.loadUrl('file://' + __dirname + '/account_setting.html');
}

app.on('ready', function() {
  appIcon = new Tray(path.join(__dirname, '../resource/icon.png'));

  reset_menu();
  appIcon.setToolTip('This is my application.');

  // Tray balloon, currently only supported in Windows.
  if (!config.username) {
    appIcon.displayBalloon({
      title: '未设置帐号',
      content: '点击这里设置帐号\n或者稍后右键点击状态栏图标 > 账号设置'
    });
  }
  appIcon.on('balloon-clicked', function () {
    account_setting();
  });

  refresh();  // First shot.

  checkForUpdates();
});

app.on('window-all-closed', function() {});
<|endoftext|>


<commit_before>/*
 * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
 *
 * @author Julius Härtl <jus@bitgrid.net>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

import app from '../app/App.js';
import CommentCollection from '../legacy/commentcollection';
import CommentModel from '../legacy/commentmodel';

const DECK_ACTIVITY_TYPE_BOARD = 'deck_board';
const DECK_ACTIVITY_TYPE_CARD = 'deck_card';

/* global OC oc_requesttoken */
class ActivityService {

	static get RESULT_PER_PAGE() { return 50; }

	constructor ($rootScope, $filter, $http, $q) {
		this.running = false;
		this.runningNewer = false;
		this.$filter = $filter;
		this.$http = $http;
		this.$q = $q;
		this.$rootScope = $rootScope;
		this.data = {};
		this.data[DECK_ACTIVITY_TYPE_BOARD] = {};
		this.data[DECK_ACTIVITY_TYPE_CARD] = {};
		this.toEnhanceWithComments = [];
		this.commentCollection = new CommentCollection();
		this.commentCollection._limit = ActivityService.RESULT_PER_PAGE;
		this.commentCollection.on('request', function() {
		}, this);
		this.commentCollection.on('sync', function(a) {
			for (let index in this.toEnhanceWithComments) {
				if (this.toEnhanceWithComments.hasOwnProperty(index)) {
					let item = this.toEnhanceWithComments[index];
					item.commentModel = this.commentCollection.get(item.subject_rich[1].comment);
					if (typeof item.commentModel !== 'undefined') {
						this.toEnhanceWithComments = this.toEnhanceWithComments.filter((entry) => entry.activity_id !== item.activity_id);
					}
				}
			}
			var firstUnread = this.commentCollection.findWhere({isUnread: true});
			if (typeof firstUnread !== 'undefined') {
				this.commentCollection.updateReadMarker();
			}
			this.notify();
		}, this);
		this.commentCollection.on('add', function(model, collection, options) {
			// we need to update the model, because it consists of client data
			// only, but the server might add meta data, e.g. about mentions
			model.fetch();
		}, this);
		this.since = {
			deck_card: {

			},
			deck_board: {

			},
		};
	}

	/**
	 * We need a event here to properly update scope once the external data from
	 * the comments backbone js code has changed
	 */
	subscribe(scope, callback) {
		let handler = this.$rootScope.$on('notify-comment-update', callback);
		scope.$on('$destroy', handler);
	}

	notify() {
		this.$rootScope.$emit('notify-comment-update');
	}

	static getUrl(type, id, since) {
		if (type === DECK_ACTIVITY_TYPE_CARD) {
			return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'filter?format=json&object_type=deck_card&object_id=' + id + '&limit=' + this.RESULT_PER_PAGE + '&since=' + since;
		}
		if (type === DECK_ACTIVITY_TYPE_BOARD) {
			return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'deck?format=json&limit=' + this.RESULT_PER_PAGE + '&since=' + since;
		}
	}

	fetchCardActivities(type, id, since) {
		this.running = true;

		this.checkData(type, id);
		const self = this;
		return this.$http.get(ActivityService.getUrl(type, id, since)).then(function (response) {
			const objects = response.data.ocs.data;

			for (let index in objects) {
				if (objects.hasOwnProperty(index)) {
					let item = objects[index];
					self.addItem(type, id, item);
					if (item.activity_id > self.since[type][id].latest) {
						self.since[type][id].latest = item.activity_id;
					}
				}
			}
			self.data[type][id].sort(function(a, b) {
				return b.activity_id - a.activity_id;
			});
			self.since[type][id].oldest = response.headers('X-Activity-Last-Given');
			self.running = false;
			return response;
		}, function (error) {
			if (error.status === 304 || error.status === 404) {
				self.since[type][id].finished = true;
			}
			self.running = false;
		});
	}

	fetchMoreActivities(type, id, success) {
		const self = this;
		this.checkData(type, id);
		if (this.running === true) {
			return this.runningPromise;
		}
		if (!this.since[type][id].finished) {
			this.runningPromise = this.fetchCardActivities(type, id, this.since[type][id].oldest);
			this.runningPromise.then(function() {
				if (type === 'deck_card') {
					self.commentCollection.fetchNext();
				}
			});
			return this.runningPromise;
		}
		return Promise.reject();
	}
	checkData(type, id) {
		if (!Array.isArray(this.data[type][id])) {
			this.data[type][id] = [];
		}
		if (typeof this.since[type][id] === 'undefined') {
			this.since[type][id] = {
				latest: -1,
				oldestCatchedUp: false,
				oldest: '0',
				finished: false,
			};
		}
	}

	addItem(type, id, item) {
		const self = this;
		const existingEntry = this.data[type][id].findIndex((entry) => { return entry.activity_id === item.activity_id; });
		if (existingEntry !== -1) {
			return;
		}
		/** check if the fetched item from all deck activities is actually related */
		const isUnrelatedBoard = (item.object_type === DECK_ACTIVITY_TYPE_BOARD && item.object_id !== id);
		const isUnrelatedCard = (item.object_type === DECK_ACTIVITY_TYPE_CARD && item.subject_rich[1].board && item.subject_rich[1].board.id !== id);
		if (type === DECK_ACTIVITY_TYPE_BOARD && (isUnrelatedBoard || isUnrelatedCard)) {
			return;
		}
		item.timestamp = new Date(item.datetime).getTime();
		item.type = 'activity';
		if (item.subject_rich[1].comment) {
			item.type = 'comment';
			item.commentModel = this.commentCollection.get(item.subject_rich[1].comment);
			if (typeof item.commentModel === 'undefined') {
				this.toEnhanceWithComments.push(item);
			}
		}

		this.data[type][id].push(item);
	}

	/**
	 * Fetch newer activities starting from the latest ones that are in cache
	 *
	 * @param type
	 * @param id
	 */
	fetchNewerActivities(type, id) {
		if (this.since[type][id].latest === 0) {
			return Promise.resolve();
		}
		let self = this;
		return this.fetchNewer(type, id).then(function() {
			return self.fetchNewerActivities(type, id);
		});
	}

	fetchNewer(type, id) {
		const deferred = this.$q.defer();
		this.running = true;
		this.runningNewer = true;
		const self = this;
		this.$http.get(ActivityService.getUrl(type, id, this.since[type][id].latest) + '&sort=asc').then(function (response) {
			let objects = response.data.ocs.data;

			let data = [];
			for (let index in objects) {
				if (objects.hasOwnProperty(index)) {
					let item = objects[index];
					self.addItem(type, id, item);
				}
			}
			self.data[type][id].sort(function(a, b) {
				return b.activity_id - a.activity_id;
			});
			self.since[type][id].latest = response.headers('X-Activity-Last-Given');
			self.data[type][id] = data.concat(self.data[type][id]);
			self.running = false;
			self.runningNewer = false;
			deferred.resolve(objects);
		}, function (error) {
			self.runningNewer = false;
			self.running = false;
		});
		return deferred.promise;
	}

	getData(type, id) {
		if (!Array.isArray(this.data[type][id])) {
			return [];
		}
		return this.data[type][id];
	}

	loadComments(id) {
		this.commentCollection.reset();
		this.commentCollection.setObjectId(id);
	}

}

app.service('ActivityService', ActivityService);

export default ActivityService;
export {DECK_ACTIVITY_TYPE_BOARD, DECK_ACTIVITY_TYPE_CARD};
<commit_msg>Do not show comments in board timeline<commit_after>/*
 * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
 *
 * @author Julius Härtl <jus@bitgrid.net>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

import app from '../app/App.js';
import CommentCollection from '../legacy/commentcollection';
import CommentModel from '../legacy/commentmodel';

const DECK_ACTIVITY_TYPE_BOARD = 'deck_board';
const DECK_ACTIVITY_TYPE_CARD = 'deck_card';

/* global OC oc_requesttoken */
class ActivityService {

	static get RESULT_PER_PAGE() { return 50; }

	constructor ($rootScope, $filter, $http, $q) {
		this.running = false;
		this.runningNewer = false;
		this.$filter = $filter;
		this.$http = $http;
		this.$q = $q;
		this.$rootScope = $rootScope;
		this.data = {};
		this.data[DECK_ACTIVITY_TYPE_BOARD] = {};
		this.data[DECK_ACTIVITY_TYPE_CARD] = {};
		this.toEnhanceWithComments = [];
		this.commentCollection = new CommentCollection();
		this.commentCollection._limit = ActivityService.RESULT_PER_PAGE;
		this.commentCollection.on('request', function() {
		}, this);
		this.commentCollection.on('sync', function(a) {
			for (let index in this.toEnhanceWithComments) {
				if (this.toEnhanceWithComments.hasOwnProperty(index)) {
					let item = this.toEnhanceWithComments[index];
					item.commentModel = this.commentCollection.get(item.subject_rich[1].comment);
					if (typeof item.commentModel !== 'undefined') {
						this.toEnhanceWithComments = this.toEnhanceWithComments.filter((entry) => entry.activity_id !== item.activity_id);
					}
				}
			}
			var firstUnread = this.commentCollection.findWhere({isUnread: true});
			if (typeof firstUnread !== 'undefined') {
				this.commentCollection.updateReadMarker();
			}
			this.notify();
		}, this);
		this.commentCollection.on('add', function(model, collection, options) {
			// we need to update the model, because it consists of client data
			// only, but the server might add meta data, e.g. about mentions
			model.fetch();
		}, this);
		this.since = {
			deck_card: {

			},
			deck_board: {

			},
		};
	}

	/**
	 * We need a event here to properly update scope once the external data from
	 * the comments backbone js code has changed
	 */
	subscribe(scope, callback) {
		let handler = this.$rootScope.$on('notify-comment-update', callback);
		scope.$on('$destroy', handler);
	}

	notify() {
		this.$rootScope.$emit('notify-comment-update');
	}

	static getUrl(type, id, since) {
		if (type === DECK_ACTIVITY_TYPE_CARD) {
			return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'filter?format=json&object_type=deck_card&object_id=' + id + '&limit=' + this.RESULT_PER_PAGE + '&since=' + since;
		}
		if (type === DECK_ACTIVITY_TYPE_BOARD) {
			return OC.linkToOCS('apps/activity/api/v2/activity', 2) + 'deck?format=json&limit=' + this.RESULT_PER_PAGE + '&since=' + since;
		}
	}

	fetchCardActivities(type, id, since) {
		this.running = true;

		this.checkData(type, id);
		const self = this;
		return this.$http.get(ActivityService.getUrl(type, id, since)).then(function (response) {
			const objects = response.data.ocs.data;

			for (let index in objects) {
				if (objects.hasOwnProperty(index)) {
					let item = objects[index];
					self.addItem(type, id, item);
					if (item.activity_id > self.since[type][id].latest) {
						self.since[type][id].latest = item.activity_id;
					}
				}
			}
			self.data[type][id].sort(function(a, b) {
				return b.activity_id - a.activity_id;
			});
			self.since[type][id].oldest = response.headers('X-Activity-Last-Given');
			self.running = false;
			return response;
		}, function (error) {
			if (error.status === 304 || error.status === 404) {
				self.since[type][id].finished = true;
			}
			self.running = false;
		});
	}

	fetchMoreActivities(type, id, success) {
		const self = this;
		this.checkData(type, id);
		if (this.running === true) {
			return this.runningPromise;
		}
		if (!this.since[type][id].finished) {
			this.runningPromise = this.fetchCardActivities(type, id, this.since[type][id].oldest);
			this.runningPromise.then(function() {
				if (type === 'deck_card') {
					self.commentCollection.fetchNext();
				}
			});
			return this.runningPromise;
		}
		return Promise.reject();
	}
	checkData(type, id) {
		if (!Array.isArray(this.data[type][id])) {
			this.data[type][id] = [];
		}
		if (typeof this.since[type][id] === 'undefined') {
			this.since[type][id] = {
				latest: -1,
				oldestCatchedUp: false,
				oldest: '0',
				finished: false,
			};
		}
	}

	addItem(type, id, item) {
		const self = this;
		const existingEntry = this.data[type][id].findIndex((entry) => { return entry.activity_id === item.activity_id; });
		if (existingEntry !== -1) {
			return;
		}
		/** check if the fetched item from all deck activities is actually related */
		const isUnrelatedBoard = (item.object_type === DECK_ACTIVITY_TYPE_BOARD && item.object_id !== id);
		const isUnrelatedCard = (item.object_type === DECK_ACTIVITY_TYPE_CARD && (
			(item.subject_rich[1].board && item.subject_rich[1].board.id !== id) || (typeof item.subject_rich[1].board === 'undefined'))
		);
		if (type === DECK_ACTIVITY_TYPE_BOARD && (isUnrelatedBoard || isUnrelatedCard)) {
			return;
		}
		item.timestamp = new Date(item.datetime).getTime();
		item.type = 'activity';
		if (item.subject_rich[1].comment) {
			item.type = 'comment';
			item.commentModel = this.commentCollection.get(item.subject_rich[1].comment);
			if (typeof item.commentModel === 'undefined') {
				this.toEnhanceWithComments.push(item);
			}
		}

		this.data[type][id].push(item);
	}

	/**
	 * Fetch newer activities starting from the latest ones that are in cache
	 *
	 * @param type
	 * @param id
	 */
	fetchNewerActivities(type, id) {
		if (this.since[type][id].latest === 0) {
			return Promise.resolve();
		}
		let self = this;
		return this.fetchNewer(type, id).then(function() {
			return self.fetchNewerActivities(type, id);
		});
	}

	fetchNewer(type, id) {
		const deferred = this.$q.defer();
		this.running = true;
		this.runningNewer = true;
		const self = this;
		this.$http.get(ActivityService.getUrl(type, id, this.since[type][id].latest) + '&sort=asc').then(function (response) {
			let objects = response.data.ocs.data;

			let data = [];
			for (let index in objects) {
				if (objects.hasOwnProperty(index)) {
					let item = objects[index];
					self.addItem(type, id, item);
				}
			}
			self.data[type][id].sort(function(a, b) {
				return b.activity_id - a.activity_id;
			});
			self.since[type][id].latest = response.headers('X-Activity-Last-Given');
			self.data[type][id] = data.concat(self.data[type][id]);
			self.running = false;
			self.runningNewer = false;
			deferred.resolve(objects);
		}, function (error) {
			self.runningNewer = false;
			self.running = false;
		});
		return deferred.promise;
	}

	getData(type, id) {
		if (!Array.isArray(this.data[type][id])) {
			return [];
		}
		return this.data[type][id];
	}

	loadComments(id) {
		this.commentCollection.reset();
		this.commentCollection.setObjectId(id);
	}

}

app.service('ActivityService', ActivityService);

export default ActivityService;
export {DECK_ACTIVITY_TYPE_BOARD, DECK_ACTIVITY_TYPE_CARD};
<|endoftext|>


<commit_before>#!/usr/bin/env node

var Rx = require('rx');
var Promise = require('bluebird');
var program = require('commander');
var _ = require('lodash');
var chalk = require('chalk');
var spawn = Promise.promisifyAll(require('cross-spawn'));
require('./lodash-mixins');

var config = {
    // Kill other processes if one dies
    killOthers: false,

    // How much in ms we wait before killing other processes
    killDelay: 1000,

    // Prefix logging with pid
    // Possible values: 'pid', 'none', 'command', 'index'
    prefix: 'index',

    // How many characters to display from start of command in prefix if
    // command is defined. Note that also '..' will be added in the middle
    prefixLength: 10,

    // By default, color output
    color: true,

    // If true, the output will only be raw output of processes, nothing more
    raw: false
};

function main() {
    parseArgs();
    config = mergeDefaultsWithArgs(config);
    run(program.args);
}

function parseArgs() {
    program
        .version(require('../package.json').version)
        .usage('[options] <command ...>')
        .option(
            '-k, --kill-others',
            'kill other processes if one exits or dies'
        )
        .option(
            '--no-color',
            'disable colors from logging'
        )
        .option(
            '-p, --prefix <prefix>',
            'prefix used in logging for each process.\n' +
            'Possible values: index, pid, command, none. Default: ' +
            config.prefix + '\n'
        )
        .option(
            '-r, --raw',
            'output only raw output of processes,' +
            ' disables prettifying and colors'
        )
        .option(
            '-l, --prefix-length <length>',
            'limit how many characters of the command is displayed in prefix.\n' +
            'The option can be used to shorten long commands.\n' +
            'Works only if prefix is set to "command". Default: ' +
            config.prefixLength + '\n'
        );

    program.on('--help', function() {
        var help = [
            '  Examples:',
            '',
            '   - Kill other processes if one exits or dies',
            '',
            '       $ concurrent --kill-others "grunt watch" "http-server"',
            '',
            '   - Output nothing more than stdout+stderr of child processes',
            '',
            '       $ concurrent --raw "npm run watch-less" "npm run watch-js"',
            '',
            '   - Normal output but without colors e.g. when logging to file',
            '',
            '       $ concurrent --no-color "grunt watch" "http-server" > log',
            ''
        ];
        console.log(help.join('\n'));

        var url = 'https://github.com/kimmobrunfeldt/concurrently';
        console.log('  For more details, visit ' + url);
        console.log('');
    });

    program.parse(process.argv);
}

function mergeDefaultsWithArgs(config) {
    // This will pollute config object with other attributes from program too
    return _.merge(config, program);
}

function run(commands) {
    var childrenInfo = {};
    var children = _.map(commands, function(cmd, index) {
        // We're splitting up the command into space-separated parts.
        // The first item is the command, all remaining items are the
        // arguments. To permit commands with spaces in the name
        // (or directory name), double slashes is a usable escape sequence.
        var escape = cmd.search('\\\s'),
            divide = cmd.search(/[^\\]\s/),
            path, args, parts;

        if (escape > -1 && divide === -1) {
            // Escaped path without arguments.
            parts = [cmd.replace('\\ ', ' ')];
        } else if (escape === -1) {
            // Not an escaped path.
            parts = cmd.split(' ');
        } else {
            // Escaped path with arguments.
            path = cmd.substr(0, divide + 1).replace('\\ ', ' ');
            args = cmd.substr(divide + 1).split(' ').filter(function(part) {
                return part.trim() != '';
            });
            parts = [path].concat(args);
        }

        var child;
        try {
            child = spawn(_.head(parts), _.tail(parts));
        } catch (e) {
            logError('', 'Error occured when executing command: ' + cmd);
            logError('', e.stack);
            process.exit(1);
        }

        childrenInfo[child.pid] = {
            command: cmd,
            index: index
        };
        return child;
    });

    // Transform all process events to rx streams
    var streams = _.map(children, function(child) {
        var streamList = [
            Rx.Node.fromReadableStream(child.stdout),
            Rx.Node.fromReadableStream(child.stderr),
            Rx.Node.fromEvent(child, 'error'),
            Rx.Node.fromEvent(child, 'close')
        ];

        var mappedStreams = _.map(streamList, function(stream) {
            return stream.map(function(data) {
                return {child: child, data: data};
            });
        });

        return {
            stdout: mappedStreams[0],
            stderr: mappedStreams[1],
            error: mappedStreams[2],
            close: mappedStreams[3]
        };
    });

    handleStdout(streams, childrenInfo);
    handleStderr(streams, childrenInfo);
    handleClose(streams, children, childrenInfo);
    handleError(streams, childrenInfo);
}

function handleStdout(streams, childrenInfo) {
    var stdoutStreams = _.pluck(streams, 'stdout');
    var stdoutStream = Rx.Observable.merge.apply(this, stdoutStreams);

    stdoutStream.subscribe(function(event) {
        var prefix = getPrefix(childrenInfo, event.child);
        log(prefix, event.data.toString());
    });
}

function handleStderr(streams, childrenInfo) {
    var stderrStreams = _.pluck(streams, 'stderr');
    var stderrStream = Rx.Observable.merge.apply(this, stderrStreams);

    stderrStream.subscribe(function(event) {
        var prefix = getPrefix(childrenInfo, event.child);
        log(prefix, event.data.toString());
    });
}

function handleClose(streams, children, childrenInfo) {
    var aliveChildren = _.clone(children);
    var exitCodes = [];

    var closeStreams = _.pluck(streams, 'close');
    var closeStream = Rx.Observable.merge.apply(this, closeStreams);

    // TODO: Is it possible that amount of close events !== count of spawned?
    closeStream.subscribe(function(event) {
        var exitCode = event.data;
        exitCodes.push(exitCode);

        var prefix = getPrefix(childrenInfo, event.child);
        var command = childrenInfo[event.child.pid].command;
        logEvent(prefix, command + ' exited with code ' + exitCode);

        aliveChildren = _.filter(aliveChildren, function(child) {
            return child.pid !== event.child.pid;
        });

        if (aliveChildren.length === 0) {
            // Final exit code is 0 when all processes ran succesfully,
            // in other cases exit code 1 is used
            var someFailed = _.some(exitCodes, function(code) {
                return code !== 0 || code === null;
            });
            var finalExitCode = someFailed ? 1 : 0;
            process.exit(finalExitCode);
        }
    });

    if (config.killOthers) {
        // Give other processes some time to stop cleanly before killing them
        var delayedExit = closeStream.delay(config.killDelay);

        delayedExit.subscribe(function() {
            logEvent('--> ', 'Sending SIGTERM to other processes..');

            // Send SIGTERM to alive children
            _.each(aliveChildren, function(child) {
                child.kill();
            });
        });
    }
}

function handleError(streams, childrenInfo) {
    // Output emitted errors from child process
    var errorStreams = _.pluck(streams, 'error');
    var processErrorStream = Rx.Observable.merge.apply(this, errorStreams);

    processErrorStream.subscribe(function(event) {
        var command = childrenInfo[event.child.pid].command;
        logError('', 'Error occured when executing command: ' + command);
        logError('', event.data.stack);
    });
}

function colorText(text, color) {
    if (!config.color) {
        return text;
    } else {
        return color(text);
    }
}

function getPrefix(childrenInfo, child) {
    if (config.prefix === 'pid') {
        return '[' + child.pid + '] ';
    } else if (config.prefix === 'command') {
        var command = childrenInfo[child.pid].command;
        return '[' + shortenText(command, config.prefixLength) + '] ';
    } else if (config.prefix === 'index') {
        return '[' + childrenInfo[child.pid].index + '] ';
    }

    return '';
}

function shortenText(text, length, cut) {
    if (text.length <= length) {
        return text;
    }
    cut = _.isString(cut) ? cut : '..';

    var endLength = Math.floor(length / 2);
    var startLength = length - endLength;

    var first = text.substring(0, startLength);
    var last = text.substring(text.length - endLength, text.length);
    return first + cut + last;
}

function log(prefix, text) {
    logWithPrefix(prefix, text);
}

function logEvent(prefix, text) {
    if (config.raw) return;

    logWithPrefix(prefix, text, chalk.gray.dim);
}

function logError(prefix, text) {
    // This is for now same as log, there might be separate colors for stderr
    // and stdout
    logWithPrefix(prefix, text, chalk.red.bold);
}

function logWithPrefix(prefix, text, color) {
    var lastChar = text[text.length - 1];
    if (config.raw) {
        if (lastChar !== '\n') {
            text += '\n';
        }

        process.stdout.write(text);
        return;
    }

    if (lastChar === '\n') {
        // Remove extra newline from the end to prevent extra newlines in input
        text = text.slice(0, text.length - 1);
    }

    var lines = text.split('\n');
    var paddedLines = _.map(lines, function(line, i) {
        var coloredLine = color ? colorText(line, color) : line;
        return colorText(prefix, chalk.gray.dim) + coloredLine;
    });

    console.log(paddedLines.join('\n'));
}

main();
<commit_msg>Clean up the structure a bit<commit_after>#!/usr/bin/env node

var Rx = require('rx');
var Promise = require('bluebird');
var program = require('commander');
var _ = require('lodash');
var chalk = require('chalk');
var spawn = Promise.promisifyAll(require('cross-spawn'));
require('./lodash-mixins');

var config = {
    // Kill other processes if one dies
    killOthers: false,

    // How much in ms we wait before killing other processes
    killDelay: 1000,

    // Prefix logging with pid
    // Possible values: 'pid', 'none', 'command', 'index'
    prefix: 'index',

    // How many characters to display from start of command in prefix if
    // command is defined. Note that also '..' will be added in the middle
    prefixLength: 10,

    // By default, color output
    color: true,

    // If true, the output will only be raw output of processes, nothing more
    raw: false
};

function main() {
    parseArgs();
    config = mergeDefaultsWithArgs(config);
    run(program.args);
}

function parseArgs() {
    program
        .version(require('../package.json').version)
        .usage('[options] <command ...>')
        .option(
            '-k, --kill-others',
            'kill other processes if one exits or dies'
        )
        .option(
            '--no-color',
            'disable colors from logging'
        )
        .option(
            '-p, --prefix <prefix>',
            'prefix used in logging for each process.\n' +
            'Possible values: index, pid, command, none. Default: ' +
            config.prefix + '\n'
        )
        .option(
            '-r, --raw',
            'output only raw output of processes,' +
            ' disables prettifying and colors'
        )
        .option(
            '-l, --prefix-length <length>',
            'limit how many characters of the command is displayed in prefix.\n' +
            'The option can be used to shorten long commands.\n' +
            'Works only if prefix is set to "command". Default: ' +
            config.prefixLength + '\n'
        );

    program.on('--help', function() {
        var help = [
            '  Examples:',
            '',
            '   - Kill other processes if one exits or dies',
            '',
            '       $ concurrent --kill-others "grunt watch" "http-server"',
            '',
            '   - Output nothing more than stdout+stderr of child processes',
            '',
            '       $ concurrent --raw "npm run watch-less" "npm run watch-js"',
            '',
            '   - Normal output but without colors e.g. when logging to file',
            '',
            '       $ concurrent --no-color "grunt watch" "http-server" > log',
            ''
        ];
        console.log(help.join('\n'));

        var url = 'https://github.com/kimmobrunfeldt/concurrently';
        console.log('  For more details, visit ' + url);
        console.log('');
    });

    program.parse(process.argv);
}

function mergeDefaultsWithArgs(config) {
    // This will pollute config object with other attributes from program too
    return _.merge(config, program);
}

function stripCmdQuotes(cmd) {
    // Removes the quotes surrounding a command.
    if (cmd[0] === '"' || cmd[0] === '\'') {
        return cmd.substr(1, cmd.length - 2);
    }
}

function separateCmdArgs(cmd) {
    // We're splitting up the command into space-separated parts.
    // The first item is the command, all remaining items are the
    // arguments. To permit commands with spaces in the name
    // (or directory name), double slashes is a usable escape sequence.
    var escape = cmd.search('\\\s'),
        divide = cmd.search(/[^\\]\s/),
        path, args, parts;

    if (escape === -1) {
        // Not an escaped path. Most common case.
        parts = cmd.split(' ');
    } else if (escape > -1 && divide === -1) {
        // Escaped path without arguments.
        parts = [cmd.replace('\\ ', ' ')];
    } else {
        // Escaped path with arguments.
        path = cmd.substr(0, divide + 1).replace('\\ ', ' ');
        args = cmd.substr(divide + 1).split(' ').filter(function(part) {
            return part.trim() != '';
        });
        parts = [path].concat(args);
    }

    // Parts contains the command as the first item and any arguments
    // as subsequent items.
    return parts;
}

function run(commands) {
    var childrenInfo = {};
    var children = _.map(commands, function(cmd, index) {
        // Remove quotes.
        cmd = stripCmdQuotes(cmd);

        // Split the command up in the command path and its arguments.
        parts = separateCmdArgs(cmd);

        var child;
        try {
            child = spawn(_.head(parts), _.tail(parts));
        } catch (e) {
            logError('', 'Error occured when executing command: ' + cmd);
            logError('', e.stack);
            process.exit(1);
        }

        childrenInfo[child.pid] = {
            command: cmd,
            index: index
        };
        return child;
    });

    // Transform all process events to rx streams
    var streams = _.map(children, function(child) {
        var streamList = [
            Rx.Node.fromReadableStream(child.stdout),
            Rx.Node.fromReadableStream(child.stderr),
            Rx.Node.fromEvent(child, 'error'),
            Rx.Node.fromEvent(child, 'close')
        ];

        var mappedStreams = _.map(streamList, function(stream) {
            return stream.map(function(data) {
                return {child: child, data: data};
            });
        });

        return {
            stdout: mappedStreams[0],
            stderr: mappedStreams[1],
            error: mappedStreams[2],
            close: mappedStreams[3]
        };
    });

    handleStdout(streams, childrenInfo);
    handleStderr(streams, childrenInfo);
    handleClose(streams, children, childrenInfo);
    handleError(streams, childrenInfo);
}

function handleStdout(streams, childrenInfo) {
    var stdoutStreams = _.pluck(streams, 'stdout');
    var stdoutStream = Rx.Observable.merge.apply(this, stdoutStreams);

    stdoutStream.subscribe(function(event) {
        var prefix = getPrefix(childrenInfo, event.child);
        log(prefix, event.data.toString());
    });
}

function handleStderr(streams, childrenInfo) {
    var stderrStreams = _.pluck(streams, 'stderr');
    var stderrStream = Rx.Observable.merge.apply(this, stderrStreams);

    stderrStream.subscribe(function(event) {
        var prefix = getPrefix(childrenInfo, event.child);
        log(prefix, event.data.toString());
    });
}

function handleClose(streams, children, childrenInfo) {
    var aliveChildren = _.clone(children);
    var exitCodes = [];

    var closeStreams = _.pluck(streams, 'close');
    var closeStream = Rx.Observable.merge.apply(this, closeStreams);

    // TODO: Is it possible that amount of close events !== count of spawned?
    closeStream.subscribe(function(event) {
        var exitCode = event.data;
        exitCodes.push(exitCode);

        var prefix = getPrefix(childrenInfo, event.child);
        var command = childrenInfo[event.child.pid].command;
        logEvent(prefix, command + ' exited with code ' + exitCode);

        aliveChildren = _.filter(aliveChildren, function(child) {
            return child.pid !== event.child.pid;
        });

        if (aliveChildren.length === 0) {
            // Final exit code is 0 when all processes ran succesfully,
            // in other cases exit code 1 is used
            var someFailed = _.some(exitCodes, function(code) {
                return code !== 0 || code === null;
            });
            var finalExitCode = someFailed ? 1 : 0;
            process.exit(finalExitCode);
        }
    });

    if (config.killOthers) {
        // Give other processes some time to stop cleanly before killing them
        var delayedExit = closeStream.delay(config.killDelay);

        delayedExit.subscribe(function() {
            logEvent('--> ', 'Sending SIGTERM to other processes..');

            // Send SIGTERM to alive children
            _.each(aliveChildren, function(child) {
                child.kill();
            });
        });
    }
}

function handleError(streams, childrenInfo) {
    // Output emitted errors from child process
    var errorStreams = _.pluck(streams, 'error');
    var processErrorStream = Rx.Observable.merge.apply(this, errorStreams);

    processErrorStream.subscribe(function(event) {
        var command = childrenInfo[event.child.pid].command;
        logError('', 'Error occured when executing command: ' + command);
        logError('', event.data.stack);
    });
}

function colorText(text, color) {
    if (!config.color) {
        return text;
    } else {
        return color(text);
    }
}

function getPrefix(childrenInfo, child) {
    if (config.prefix === 'pid') {
        return '[' + child.pid + '] ';
    } else if (config.prefix === 'command') {
        var command = childrenInfo[child.pid].command;
        return '[' + shortenText(command, config.prefixLength) + '] ';
    } else if (config.prefix === 'index') {
        return '[' + childrenInfo[child.pid].index + '] ';
    }

    return '';
}

function shortenText(text, length, cut) {
    if (text.length <= length) {
        return text;
    }
    cut = _.isString(cut) ? cut : '..';

    var endLength = Math.floor(length / 2);
    var startLength = length - endLength;

    var first = text.substring(0, startLength);
    var last = text.substring(text.length - endLength, text.length);
    return first + cut + last;
}

function log(prefix, text) {
    logWithPrefix(prefix, text);
}

function logEvent(prefix, text) {
    if (config.raw) return;

    logWithPrefix(prefix, text, chalk.gray.dim);
}

function logError(prefix, text) {
    // This is for now same as log, there might be separate colors for stderr
    // and stdout
    logWithPrefix(prefix, text, chalk.red.bold);
}

function logWithPrefix(prefix, text, color) {
    var lastChar = text[text.length - 1];
    if (config.raw) {
        if (lastChar !== '\n') {
            text += '\n';
        }

        process.stdout.write(text);
        return;
    }

    if (lastChar === '\n') {
        // Remove extra newline from the end to prevent extra newlines in input
        text = text.slice(0, text.length - 1);
    }

    var lines = text.split('\n');
    var paddedLines = _.map(lines, function(line, i) {
        var coloredLine = color ? colorText(line, color) : line;
        return colorText(prefix, chalk.gray.dim) + coloredLine;
    });

    console.log(paddedLines.join('\n'));
}

main();
<|endoftext|>


<commit_before><commit_msg>improve values mouseover display<commit_after><|endoftext|>