<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/** @suppress {duplicate} */
var remoting = remoting || {};

/**
 * @param {Array.<remoting.HostSetupFlow.State>} sequence Sequence of
 * steps for the flow.
 * @constructor
 */
remoting.HostSetupFlow = function(sequence) {
  this.sequence_ = sequence;
  this.currentStep_ = 0;
  this.state_ = sequence[0];

  this.pin = '';
  this.hostConfig = '';
};

/** @enum {number} */
remoting.HostSetupFlow.State = {
  NONE: 0,
  ASK_PIN: 1,
  REGISTER_HOST: 2,
  START_HOST: 3,
  HOST_STARTED: 4,
  UPDATE_PIN: 5,
  REGISTRATION_FAILED: 6,
  HOST_START_FAILED: 7
};

/** @return {remoting.HostSetupFlow.State} Current state of the flow. */
remoting.HostSetupFlow.prototype.getState = function() {
  return this.state_;
};

/**
 * @param {boolean} success
 * @return {remoting.HostSetupFlow.State} New state.
 */
remoting.HostSetupFlow.prototype.switchToNextStep = function(success) {
  if (this.state_ == remoting.HostSetupFlow.State.NONE) {
    return this.state_;
  }
  if (success) {
    // If the current step was successful then switch to the next
    // step in the sequence.
    if (this.currentStep_ < this.sequence_.length - 1) {
      this.currentStep_ += 1;
      this.state_ = this.sequence_[this.currentStep_];
    } else {
      this.state_ = remoting.HostSetupFlow.State.NONE;
    }
  } else {
    // Current step failed, so switch to corresponding error state.
    if (this.state_ == remoting.HostSetupFlow.State.REGISTER_HOST) {
      this.state_ = remoting.HostSetupFlow.State.REGISTRATION_FAILED;
    } else {
      // TODO(sergeyu): Add other error states and use them here.
      this.state_ = remoting.HostSetupFlow.State.HOST_START_FAILED;
    }
  }
  return this.state_;
};

/**
 * @param {remoting.DaemonPlugin} daemon The parent daemon plugin instance.
 * @constructor
 */
remoting.HostSetupDialog = function(daemon) {
  this.daemon_ = daemon;
  this.pinEntry_ = document.getElementById('daemon-pin-entry');
  this.pinConfirm_ = document.getElementById('daemon-pin-confirm');

  /** @type {remoting.HostSetupFlow} */
  this.flow_ = new remoting.HostSetupFlow([remoting.HostSetupFlow.State.NONE]);

  /** @type {remoting.HostSetupDialog} */
  var that = this;
  /** @param {Event} event The event. */
  var onPinSubmit = function(event) {
    event.preventDefault();
    that.onPinSubmit_();
  };
  var form = document.getElementById('ask-pin-form');
  form.addEventListener('submit', onPinSubmit, false);
};

/**
 * Show the dialog in order to get a PIN prior to starting the daemon. When the
 * user clicks OK, the dialog shows a spinner until the daemon has started.
 *
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.showForStart = function() {
  this.startNewFlow_(
      [remoting.HostSetupFlow.State.ASK_PIN,
       remoting.HostSetupFlow.State.REGISTER_HOST,
       remoting.HostSetupFlow.State.START_HOST,
       remoting.HostSetupFlow.State.HOST_STARTED]);
};

/**
 * Show the dialog in order to change the PIN associated with a running daemon.
 *
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.showForPin = function() {
  this.startNewFlow_(
      [remoting.HostSetupFlow.State.ASK_PIN,
       remoting.HostSetupFlow.State.UPDATE_PIN]);
};

/**
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.hide = function() {
  remoting.setMode(remoting.AppMode.HOME);
};

/**
 * Starts new flow with the specified sequence of steps.
 * @param {Array.<remoting.HostSetupFlow.State>} sequence Sequence of steps.
 * @private
 */
remoting.HostSetupDialog.prototype.startNewFlow_ = function(sequence) {
  this.flow_ = new remoting.HostSetupFlow(sequence);
  this.pinEntry_.text = '';
  this.pinConfirm_.text = '';
  this.updateState_();
};

/**
 * Updates current UI mode according to the current state of the setup
 * flow and start the action corresponding to the current step (if
 * any).
 * @private
 */
remoting.HostSetupDialog.prototype.updateState_ = function() {
  /** @param {string} tag */
  function showProcessingMessage(tag) {
    var errorDiv = document.getElementById('host-setup-processing-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_PROCESSING);
  }
  /** @param {string} tag */
  function showDoneMessage(tag) {
    var errorDiv = document.getElementById('host-setup-done-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_DONE);
  }
  /** @param {string} tag */
  function showErrorMessage(tag) {
    var errorDiv = document.getElementById('host-setup-error-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_ERROR);
  }

  var state = this.flow_.getState();
  if (state == remoting.HostSetupFlow.State.NONE) {
    this.hide();
  } else if (state == remoting.HostSetupFlow.State.ASK_PIN) {
    remoting.setMode(remoting.AppMode.HOST_SETUP_ASK_PIN);
  } else if (state == remoting.HostSetupFlow.State.REGISTER_HOST) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_STARTING');
    this.registerHost_();
  } else if (state == remoting.HostSetupFlow.State.START_HOST) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_STARTING');
    this.startHost_();
  } else if (state == remoting.HostSetupFlow.State.UPDATE_PIN) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_UPDATING_PIN');
    this.updatePin_();
  } else if (state == remoting.HostSetupFlow.State.HOST_STARTED) {
    showDoneMessage(/*i18n-content*/'HOST_SETUP_STARTED');
  } else if (state == remoting.HostSetupFlow.State.REGISTRATION_FAILED) {
    showErrorMessage(/*i18n-content*/'HOST_SETUP_REGISTRATION_FAILED');
  } else if (state == remoting.HostSetupFlow.State.HOST_START_FAILED) {
    showErrorMessage(/*i18n-content*/'HOST_SETUP_HOST_FAILED');
  }
};

/**
 * Registers new host.
 */
remoting.HostSetupDialog.prototype.registerHost_ = function() {
  /** @type {remoting.HostSetupDialog} */
  var that = this;
  /** @type {remoting.HostSetupFlow} */
  var flow = this.flow_;

  /** @return {string} */
  function generateUuid() {
    var random = new Uint16Array(8);
    window.crypto.getRandomValues(random);
    /** @type {Array.<string>} */
    var e = new Array();
    for (var i = 0; i < 8; i++) {
      e[i] = (/** @type {number} */random[i] + 0x10000).
          toString(16).substring(1);
    }
    return e[0] + e[1] + '-' + e[2] + "-" + e[3] + '-' +
        e[4] + '-' + e[5] + e[6] + e[7];
  }

  var newHostId = generateUuid();

  /** @param {string} privateKey
   *  @param {XMLHttpRequest} xhr */
  function onRegistered(privateKey, xhr) {
    if (flow !== that.flow_ ||
        flow.getState() != remoting.HostSetupFlow.State.REGISTER_HOST) {
      console.error('Host setup was interrupted when registering the host');
      return;
    }

    var success = (xhr.status == 200);

    if (success) {
      // TODO(sergeyu): Calculate HMAC of the PIN instead of storing it
      // in plaintext.
      flow.hostConfig = JSON.stringify({
          xmpp_login: remoting.oauth2.getCachedEmail(),
          oauth_refresh_token: remoting.oauth2.getRefreshToken(),
          host_id: newHostId,
          host_name: that.daemon_.getHostName(),
          host_secret_hash: 'plain:' + flow.pin,
          private_key: privateKey
        });
    } else {
      console.log('Failed to register the host. Status: ' + xhr.status +
                  ' response: ' + xhr.responseText);
    }

    flow.switchToNextStep(success);
    that.updateState_();
  }

  /**
   * @param {string} privateKey
   * @param {string} publicKey
   * @param {string} oauthToken
   */
  function doRegisterHost(privateKey, publicKey, oauthToken) {
    if (flow !== that.flow_ ||
        flow.getState() != remoting.HostSetupFlow.State.REGISTER_HOST) {
      console.error('Host setup was interrupted when generating key pair');
      return;
    }

    var headers = {
      'Authorization': 'OAuth ' + oauthToken,
      'Content-type' : 'application/json; charset=UTF-8'
    };

    var newHostDetails = { data: {
       hostId: newHostId,
       hostName: that.daemon_.getHostName(),
       publicKey: publicKey
    } };
    remoting.xhr.post(
        'https://www.googleapis.com/chromoting/v1/@me/hosts/',
        /** @param {XMLHttpRequest} xhr */
        function (xhr) { onRegistered(privateKey, xhr); },
        JSON.stringify(newHostDetails),
        headers);
  }

  this.daemon_.generateKeyPair(
      /** @param {string} privateKey
       *  @param {string} publicKey */
      function(privateKey, publicKey) {
      remoting.oauth2.callWithToken(
          /** @param {string} oauthToken */
          function(oauthToken) {
            doRegisterHost(privateKey, publicKey, oauthToken);
          });
      });
};

/**
 * Starts the host process after it's registered.
 */
remoting.HostSetupDialog.prototype.startHost_ = function() {
  this.daemon_.start(this.flow_.hostConfig);
  this.pollDaemonState_();
};

remoting.HostSetupDialog.prototype.updatePin_ = function() {
  this.daemon_.setPin(this.flow_.pin);
  this.pollDaemonState_();
}

/** @private */
remoting.HostSetupDialog.prototype.onPinSubmit_ = function() {
  if (this.flow_.getState() != remoting.HostSetupFlow.State.ASK_PIN) {
    console.error('PIN submitted in an invalid state', this.flow_.getState());
    return;
  }
  // TODO(jamiewalch): Add validation and error checks when we improve the UI.
  var pin = this.pinEntry_.value;
  this.flow_.pin = pin;
  this.flow_.switchToNextStep(true);
  this.updateState_();
};

/**
 * @return {void} Nothing.
 * @private
 */
remoting.HostSetupDialog.prototype.pollDaemonState_ = function() {
  var state = this.daemon_.state();
  var retry = false;  // Set to true if we haven't finished yet.
  switch (state) {
    case remoting.DaemonPlugin.State.STOPPED:
    case remoting.DaemonPlugin.State.NOT_INSTALLED:
      retry = true;
      break;
    case remoting.DaemonPlugin.State.STARTED:
      if (this.flow_.getState() == remoting.HostSetupFlow.State.START_HOST ||
          this.flow_.getState() == remoting.HostSetupFlow.State.UPDATE_PIN) {
        this.flow_.switchToNextStep(true);
        this.updateState_();
      }
      this.daemon_.updateDom();
      break;
    case remoting.DaemonPlugin.State.START_FAILED:
      if (this.flow_.getState() == remoting.HostSetupFlow.State.START_HOST ||
          this.flow_.getState() == remoting.HostSetupFlow.State.UPDATE_PIN) {
        this.flow_.switchToNextStep(false);
        this.updateState_();
      }
      break;
    default:
      // TODO(jamiewalch): Show an error message.
      console.error('Unexpected daemon state', state);
      break;
  }
  if (retry) {
    /** @type {remoting.HostSetupDialog} */
    var that = this;
    var pollDaemonState = function() { that.pollDaemonState_(); }
    window.setTimeout(pollDaemonState, 1000);
  }
};

/** @type {remoting.HostSetupDialog} */
remoting.hostSetupDialog = null;
<commit_msg>Apply BASE64 encoding to PIN before storing it in the config file.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

'use strict';

/** @suppress {duplicate} */
var remoting = remoting || {};

/**
 * @param {Array.<remoting.HostSetupFlow.State>} sequence Sequence of
 * steps for the flow.
 * @constructor
 */
remoting.HostSetupFlow = function(sequence) {
  this.sequence_ = sequence;
  this.currentStep_ = 0;
  this.state_ = sequence[0];

  this.pin = '';
  this.hostConfig = '';
};

/** @enum {number} */
remoting.HostSetupFlow.State = {
  NONE: 0,
  ASK_PIN: 1,
  REGISTER_HOST: 2,
  START_HOST: 3,
  HOST_STARTED: 4,
  UPDATE_PIN: 5,
  REGISTRATION_FAILED: 6,
  HOST_START_FAILED: 7
};

/** @return {remoting.HostSetupFlow.State} Current state of the flow. */
remoting.HostSetupFlow.prototype.getState = function() {
  return this.state_;
};

/**
 * @param {boolean} success
 * @return {remoting.HostSetupFlow.State} New state.
 */
remoting.HostSetupFlow.prototype.switchToNextStep = function(success) {
  if (this.state_ == remoting.HostSetupFlow.State.NONE) {
    return this.state_;
  }
  if (success) {
    // If the current step was successful then switch to the next
    // step in the sequence.
    if (this.currentStep_ < this.sequence_.length - 1) {
      this.currentStep_ += 1;
      this.state_ = this.sequence_[this.currentStep_];
    } else {
      this.state_ = remoting.HostSetupFlow.State.NONE;
    }
  } else {
    // Current step failed, so switch to corresponding error state.
    if (this.state_ == remoting.HostSetupFlow.State.REGISTER_HOST) {
      this.state_ = remoting.HostSetupFlow.State.REGISTRATION_FAILED;
    } else {
      // TODO(sergeyu): Add other error states and use them here.
      this.state_ = remoting.HostSetupFlow.State.HOST_START_FAILED;
    }
  }
  return this.state_;
};

/**
 * @param {remoting.DaemonPlugin} daemon The parent daemon plugin instance.
 * @constructor
 */
remoting.HostSetupDialog = function(daemon) {
  this.daemon_ = daemon;
  this.pinEntry_ = document.getElementById('daemon-pin-entry');
  this.pinConfirm_ = document.getElementById('daemon-pin-confirm');

  /** @type {remoting.HostSetupFlow} */
  this.flow_ = new remoting.HostSetupFlow([remoting.HostSetupFlow.State.NONE]);

  /** @type {remoting.HostSetupDialog} */
  var that = this;
  /** @param {Event} event The event. */
  var onPinSubmit = function(event) {
    event.preventDefault();
    that.onPinSubmit_();
  };
  var form = document.getElementById('ask-pin-form');
  form.addEventListener('submit', onPinSubmit, false);
};

/**
 * Show the dialog in order to get a PIN prior to starting the daemon. When the
 * user clicks OK, the dialog shows a spinner until the daemon has started.
 *
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.showForStart = function() {
  this.startNewFlow_(
      [remoting.HostSetupFlow.State.ASK_PIN,
       remoting.HostSetupFlow.State.REGISTER_HOST,
       remoting.HostSetupFlow.State.START_HOST,
       remoting.HostSetupFlow.State.HOST_STARTED]);
};

/**
 * Show the dialog in order to change the PIN associated with a running daemon.
 *
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.showForPin = function() {
  this.startNewFlow_(
      [remoting.HostSetupFlow.State.ASK_PIN,
       remoting.HostSetupFlow.State.UPDATE_PIN]);
};

/**
 * @return {void} Nothing.
 */
remoting.HostSetupDialog.prototype.hide = function() {
  remoting.setMode(remoting.AppMode.HOME);
};

/**
 * Starts new flow with the specified sequence of steps.
 * @param {Array.<remoting.HostSetupFlow.State>} sequence Sequence of steps.
 * @private
 */
remoting.HostSetupDialog.prototype.startNewFlow_ = function(sequence) {
  this.flow_ = new remoting.HostSetupFlow(sequence);
  this.pinEntry_.text = '';
  this.pinConfirm_.text = '';
  this.updateState_();
};

/**
 * Updates current UI mode according to the current state of the setup
 * flow and start the action corresponding to the current step (if
 * any).
 * @private
 */
remoting.HostSetupDialog.prototype.updateState_ = function() {
  /** @param {string} tag */
  function showProcessingMessage(tag) {
    var errorDiv = document.getElementById('host-setup-processing-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_PROCESSING);
  }
  /** @param {string} tag */
  function showDoneMessage(tag) {
    var errorDiv = document.getElementById('host-setup-done-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_DONE);
  }
  /** @param {string} tag */
  function showErrorMessage(tag) {
    var errorDiv = document.getElementById('host-setup-error-message');
    l10n.localizeElementFromTag(errorDiv, tag);
    remoting.setMode(remoting.AppMode.HOST_SETUP_ERROR);
  }

  var state = this.flow_.getState();
  if (state == remoting.HostSetupFlow.State.NONE) {
    this.hide();
  } else if (state == remoting.HostSetupFlow.State.ASK_PIN) {
    remoting.setMode(remoting.AppMode.HOST_SETUP_ASK_PIN);
  } else if (state == remoting.HostSetupFlow.State.REGISTER_HOST) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_STARTING');
    this.registerHost_();
  } else if (state == remoting.HostSetupFlow.State.START_HOST) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_STARTING');
    this.startHost_();
  } else if (state == remoting.HostSetupFlow.State.UPDATE_PIN) {
    showProcessingMessage(/*i18n-content*/'HOST_SETUP_UPDATING_PIN');
    this.updatePin_();
  } else if (state == remoting.HostSetupFlow.State.HOST_STARTED) {
    showDoneMessage(/*i18n-content*/'HOST_SETUP_STARTED');
  } else if (state == remoting.HostSetupFlow.State.REGISTRATION_FAILED) {
    showErrorMessage(/*i18n-content*/'HOST_SETUP_REGISTRATION_FAILED');
  } else if (state == remoting.HostSetupFlow.State.HOST_START_FAILED) {
    showErrorMessage(/*i18n-content*/'HOST_SETUP_HOST_FAILED');
  }
};

/**
 * Registers new host.
 */
remoting.HostSetupDialog.prototype.registerHost_ = function() {
  /** @type {remoting.HostSetupDialog} */
  var that = this;
  /** @type {remoting.HostSetupFlow} */
  var flow = this.flow_;

  /** @return {string} */
  function generateUuid() {
    var random = new Uint16Array(8);
    window.crypto.getRandomValues(random);
    /** @type {Array.<string>} */
    var e = new Array();
    for (var i = 0; i < 8; i++) {
      e[i] = (/** @type {number} */random[i] + 0x10000).
          toString(16).substring(1);
    }
    return e[0] + e[1] + '-' + e[2] + "-" + e[3] + '-' +
        e[4] + '-' + e[5] + e[6] + e[7];
  }

  var newHostId = generateUuid();

  /** @param {string} privateKey
   *  @param {XMLHttpRequest} xhr */
  function onRegistered(privateKey, xhr) {
    if (flow !== that.flow_ ||
        flow.getState() != remoting.HostSetupFlow.State.REGISTER_HOST) {
      console.error('Host setup was interrupted when registering the host');
      return;
    }

    var success = (xhr.status == 200);

    if (success) {
      // TODO(sergeyu): Calculate HMAC of the PIN instead of storing it
      // in plaintext.
      flow.hostConfig = JSON.stringify({
          xmpp_login: remoting.oauth2.getCachedEmail(),
          oauth_refresh_token: remoting.oauth2.getRefreshToken(),
          host_id: newHostId,
          host_name: that.daemon_.getHostName(),
          host_secret_hash: 'plain:' + window.btoa(flow.pin),
          private_key: privateKey
        });
    } else {
      console.log('Failed to register the host. Status: ' + xhr.status +
                  ' response: ' + xhr.responseText);
    }

    flow.switchToNextStep(success);
    that.updateState_();
  }

  /**
   * @param {string} privateKey
   * @param {string} publicKey
   * @param {string} oauthToken
   */
  function doRegisterHost(privateKey, publicKey, oauthToken) {
    if (flow !== that.flow_ ||
        flow.getState() != remoting.HostSetupFlow.State.REGISTER_HOST) {
      console.error('Host setup was interrupted when generating key pair');
      return;
    }

    var headers = {
      'Authorization': 'OAuth ' + oauthToken,
      'Content-type' : 'application/json; charset=UTF-8'
    };

    var newHostDetails = { data: {
       hostId: newHostId,
       hostName: that.daemon_.getHostName(),
       publicKey: publicKey
    } };
    remoting.xhr.post(
        'https://www.googleapis.com/chromoting/v1/@me/hosts/',
        /** @param {XMLHttpRequest} xhr */
        function (xhr) { onRegistered(privateKey, xhr); },
        JSON.stringify(newHostDetails),
        headers);
  }

  this.daemon_.generateKeyPair(
      /** @param {string} privateKey
       *  @param {string} publicKey */
      function(privateKey, publicKey) {
      remoting.oauth2.callWithToken(
          /** @param {string} oauthToken */
          function(oauthToken) {
            doRegisterHost(privateKey, publicKey, oauthToken);
          });
      });
};

/**
 * Starts the host process after it's registered.
 */
remoting.HostSetupDialog.prototype.startHost_ = function() {
  this.daemon_.start(this.flow_.hostConfig);
  this.pollDaemonState_();
};

remoting.HostSetupDialog.prototype.updatePin_ = function() {
  this.daemon_.setPin(this.flow_.pin);
  this.pollDaemonState_();
}

/** @private */
remoting.HostSetupDialog.prototype.onPinSubmit_ = function() {
  if (this.flow_.getState() != remoting.HostSetupFlow.State.ASK_PIN) {
    console.error('PIN submitted in an invalid state', this.flow_.getState());
    return;
  }
  // TODO(jamiewalch): Add validation and error checks when we improve the UI.
  var pin = this.pinEntry_.value;
  this.flow_.pin = pin;
  this.flow_.switchToNextStep(true);
  this.updateState_();
};

/**
 * @return {void} Nothing.
 * @private
 */
remoting.HostSetupDialog.prototype.pollDaemonState_ = function() {
  var state = this.daemon_.state();
  var retry = false;  // Set to true if we haven't finished yet.
  switch (state) {
    case remoting.DaemonPlugin.State.STOPPED:
    case remoting.DaemonPlugin.State.NOT_INSTALLED:
      retry = true;
      break;
    case remoting.DaemonPlugin.State.STARTED:
      if (this.flow_.getState() == remoting.HostSetupFlow.State.START_HOST ||
          this.flow_.getState() == remoting.HostSetupFlow.State.UPDATE_PIN) {
        this.flow_.switchToNextStep(true);
        this.updateState_();
      }
      this.daemon_.updateDom();
      break;
    case remoting.DaemonPlugin.State.START_FAILED:
      if (this.flow_.getState() == remoting.HostSetupFlow.State.START_HOST ||
          this.flow_.getState() == remoting.HostSetupFlow.State.UPDATE_PIN) {
        this.flow_.switchToNextStep(false);
        this.updateState_();
      }
      break;
    default:
      // TODO(jamiewalch): Show an error message.
      console.error('Unexpected daemon state', state);
      break;
  }
  if (retry) {
    /** @type {remoting.HostSetupDialog} */
    var that = this;
    var pollDaemonState = function() { that.pollDaemonState_(); }
    window.setTimeout(pollDaemonState, 1000);
  }
};

/** @type {remoting.HostSetupDialog} */
remoting.hostSetupDialog = null;
<|endoftext|>


<commit_before>/**
 * Dependencies declared
 */
import express from 'express';
import UserController from '../controllers/UserController';
import Authentication from '../middlewares/Authentication';
/**
 * Routes for user
 * @type {Object}
 */
const userRouter = express.Router();

userRouter.route('/')
  .get()
  .post();

userRouter.route('/login')
  .post();

userRouter.route('/logout')
  .post();

userRouter.get('/search');

userRouter.route('/:id')
  .get()
  .put()
  .delete();

userRouter.route('/:id/documents')
  .get();

export default userRouter;
<commit_msg>chore(routes):modify-routes -Modify user routes<commit_after>/**
 * Dependencies declared
 */
import express from 'express';
import UserController from '../controllers/UserController';
import Authentication from '../middlewares/Authentication';
/**
 * Routes for user
 * @type {Object}
 */
const userRouter = express.Router();
/**
 * Create user route
 */
userRouter.route('/')
  .get(Authentication.verifyToken,
    Authentication.validateSearch,
    UserController.getAllUser)
  .post(Authentication.verifyUserInput,
    UserController.createUser);
/**
 * Login route
 */
userRouter.route('/login')
  .post();
/**
 * Logout route
 */
userRouter.route('/logout')
  .post();
/**
 * Search user route
 */
userRouter.get('/search');

userRouter.route('/:id')
  .get()
  .put()
  .delete();

userRouter.route('/:id/documents')
  .get();

export default userRouter;
<|endoftext|>


<commit_before>#!/usr/bin/env vows
/*jslint node: true, maxlen: 150, maxerr: 50, indent: 2 */
'use strict';

var vows = require('vows'),
    assert = require('assert'),
    request = require('request'),
    async = require('async'),
    fs = require('fs'),
    querystring = require('querystring'),
    baseurl = 'http://127.0.0.1:32773',
    j1 = request.jar(),
    j2 = request.jar(),
    userdata1 = {},
    userdata2 = {},
    cid1 = 'cid_op_1',
    cid2 = 'cid_op_2';

try {
  baseurl = fs.readFileSync(__dirname + '/../../serverurl', 'utf8');
} catch (err) {}

vows.describe('First is operator tests').addBatch({

  'when a user join a channel and is alone': {
    topic: function () {
      var self = this;
      var requests = [
        // [0] auth u1
        function USER1LOGIN(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/auth',
            headers: { 'Pfc-Authorization': 'Basic '
                       + new Buffer("testop1:password").toString('base64') },
            jar: j1,
          }, function (err, res, body) {
            userdata1 = JSON.parse(body);
            callback(err, res, body);
          });
        },
        // [1] u1 join cid1
        function USER1JOIN(callback) {
          request({
            method: 'PUT',
            url: baseurl + '/server/channels/' + cid1 + '/users/' + userdata1.id,
            jar: j1,
          }, callback);
        },
      ];

      // store function names in the steps array
      // so following asserts are easier to read
      var steps = {};
      requests.forEach(function (fn, i) {
        steps[fn.name] = i;
      });

      // run the function array in a sequential order
      // each function result is stored in the 'results' array
      async.series(requests, function (error, results) {
        self.callback(error, results, requests, steps);
      });
    },

    'server returns success status codes': function (error, results, requests, steps) {
      var codes = [ 200, 201 ];
      results.forEach(function (r, i) {
        assert.equal(r[0].statusCode, codes[i], 'response ' + i + ' code is wrong (expected ' + codes[i] + ' got ' + r[0].statusCode + ')');
      });
    },

    'join command response has an operator list with the user1 id into (first_is_op feature)': function (error, results, requests, steps) {
      var join_response = {};
      try {
        join_response = JSON.parse(results[steps.USER1JOIN][0].body);
      } catch (err) {
        assert.isNull(err, 'response body should be JSON formated');
      }
      assert.lengthOf(join_response.op, 1);
      assert.include(join_response.op, userdata1.id);
    },

  },
}).export(module);
<commit_msg>tests for operator list retrieval<commit_after>#!/usr/bin/env vows
/*jslint node: true, maxlen: 150, maxerr: 50, indent: 2 */
'use strict';

var vows = require('vows'),
    assert = require('assert'),
    request = require('request'),
    async = require('async'),
    fs = require('fs'),
    querystring = require('querystring'),
    baseurl = 'http://127.0.0.1:32773',
    j1 = request.jar(),
    j2 = request.jar(),
    userdata1 = {},
    userdata2 = {},
    cid1 = 'cid_op_1',
    cid2 = 'cid_op_2';

try {
  baseurl = fs.readFileSync(__dirname + '/../../serverurl', 'utf8');
} catch (err) {}

vows.describe('First is operator tests').addBatch({

  'when user1 joins the channel (he is alone) then user2 joins the channel (they are two in the channel)': {
    topic: function () {
      var self = this;
      var requests = [

        // [0] auth u1
        function USER1LOGIN(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/auth',
            headers: { 'Pfc-Authorization': 'Basic '
                       + new Buffer("testop1:password").toString('base64') },
            jar: j1,
          }, function (err, res, body) {
            userdata1 = JSON.parse(body);
            callback(err, res, body);
          });
        },

        // [1] u1 join cid1
        function USER1JOIN(callback) {
          request({
            method: 'PUT',
            url: baseurl + '/server/channels/' + cid1 + '/users/' + userdata1.id,
            jar: j1,
          }, callback);
        },

        // [2] u1 get the operator list
        function USER1OPLIST(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/channels/' + cid1 + '/op/',
            jar: j1,
          }, callback);
        },

        // [3] auth u2
        function USER2LOGIN(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/auth',
            headers: { 'Pfc-Authorization': 'Basic '
                       + new Buffer("testop2:password").toString('base64') },
            jar: j2,
          }, function (err, res, body) {
            userdata2 = JSON.parse(body);
            callback(err, res, body);
          });
        },

        // [4] u2 get the operator list
        function USER2OPLIST1(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/channels/' + cid1 + '/op/',
            jar: j2,
          }, callback);
        },

        // [5] u2 join cid1
        function USER2JOIN(callback) {
          request({
            method: 'PUT',
            url: baseurl + '/server/channels/' + cid1 + '/users/' + userdata2.id,
            jar: j2,
          }, callback);
        },

        // [6] u2 get the operator list
        function USER2OPLIST2(callback) {
          request({
            method: 'GET',
            url: baseurl + '/server/channels/' + cid1 + '/op/',
            jar: j2,
          }, callback);
        },

      ];

      // store function names in the steps array
      // so following asserts are easier to read
      var steps = {};
      requests.forEach(function (fn, i) {
        steps[fn.name] = i;
      });

      // run the function array in a sequential order
      // each function result is stored in the 'results' array
      async.series(requests, function (error, results) {
        self.callback(error, results, requests, steps);
      });
    },

    'server returns success status codes': function (error, results, requests, steps) {
      var codes = [ 200, 201, 200, 200, 403, 201, 200 ];
      results.forEach(function (r, i) {
        assert.equal(r[0].statusCode, codes[i], 'response ' + i + ' code is wrong (expected ' + codes[i] + ' got ' + r[0].statusCode + ')');
      });
    },

    'user1 should be operator when he is alone (first_is_op feature)': function (error, results, requests, steps) {
      var join_response = {};
      try {
        join_response = JSON.parse(results[steps.USER1JOIN][0].body);
      } catch (err) {
        assert.isNull(err, 'response body should be JSON formated');
      }
      assert.lengthOf(join_response.op, 1);
      assert.include(join_response.op, userdata1.id);
    },

    'user2 should not be operator when he just joined the channel (first_is_op feature)': function (error, results, requests, steps) {
      var join_response = {};
      try {
        join_response = JSON.parse(results[steps.USER2JOIN][0].body);
      } catch (err) {
        assert.isNull(err, 'response body should be JSON formated');
      }
      assert.lengthOf(join_response.op, 1);
      assert.include(join_response.op, userdata1.id);
      assert.isTrue(join_response.op.indexOf(userdata2.id) == -1);
    },

    'user1 should be allowed to retrieve the channel operator list once he joins the channel': function (error, results, requests, steps) {
      var response = {};
      try {
        response = JSON.parse(results[steps.USER1OPLIST][0].body);
      } catch (err) {
        assert.isNull(err, 'response body should be JSON formated');
      }

      assert.isArray(response);
      assert.lengthOf(response, 1);
    },

    'user2 should not be allowed to retrieve the channel operator list if he did not joined the channel': function (error, results, requests, steps) {
      assert.equal(results[steps.USER2OPLIST1][0].statusCode, 403);
    },

    'user2 should be allowed to retrieve the channel operator list once he joined the channel': function (error, results, requests, steps) {
      assert.equal(results[steps.USER2OPLIST2][0].statusCode, 200);

      var response = {};
      try {
        response = JSON.parse(results[steps.USER2OPLIST2][0].body);
      } catch (err) {
        assert.isNull(err, 'response body should be JSON formated');
      }

      assert.isArray(response);
      assert.lengthOf(response, 1);
    },

  },
}).export(module);
<|endoftext|>


<commit_before>CT.require("CT.all");
CT.require("core");

CT.onload(function() {
	CT.initCore();
	var content = CT.dom.node(null, null, "ctcontent"),
		clist = CT.dom.node(null, null, "ctlist bigger"),
		builder = function(data) {
			CT.dom.setContent(content, data.content);
		};
	clist.appendChild(CT.panel.triggerList([
		{
			name: "plugins",
			content: "We've got some plugins, ladies and gentlemen. Click away."
		}, {
			name: "ctuser",
			content: [
				"This package includes a model, a request handler, and frontend components, including a profile page and a browsing interface, for handling user accounts.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctuser", "biggest p30 right")
			]
		}, {
			name: "ctblog",
			content: [
				"This package contains a generic blog-type website.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctblog", "biggest p30 right")
			]
		}, {
			name: "ctstore",
			content: [
				"This package enables the developer to create a basic ecommerce website with nothing but configuration.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctstore", "biggest p30 right")
			]
		}, {
			name: "ctdecide",
			content: [
				"This package provides a framework for group decision making.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctdecide", "biggest p30 right")
			]
		}, {
			name: "ctcoop",
			content: [
				"This package provides organizational management tools (in the form of web pages and components) for a cooperative.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctcoop", "biggest p30 right")
			]
		}, {
			name: "ctunes",
			content: [
				"This package contains a generic music website.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctunes", "biggest p30 right")
			]
		}, {
			name: "ctdocs",
			content: [
				"This package parses JSON-defined documentation data and displays it in a web page.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctdocs", "biggest p30 right")
			]
		}
	], builder));
	CT.dom.setContent("ctmain", [content, clist]);
	var hash = location.hash.slice(1);
	if (hash)
		CT.dom.id("tl" + hash).trigger();
	else
		CT.dom.className("tlitem")[0].trigger();
});<commit_msg>plugins: big old headers<commit_after>CT.require("CT.all");
CT.require("core");

CT.onload(function() {
	CT.initCore();
	var content = CT.dom.node(null, null, "ctcontent"),
		clist = CT.dom.node(null, null, "ctlist bigger"),
		builder = function(data) {
			CT.dom.setContent(content, [
				CT.dom.node(data.name, "div", "biggerest bold bottompadded"),
				data.content
			]);
		};
	clist.appendChild(CT.panel.triggerList([
		{
			name: "plugins",
			content: "We've got some plugins, ladies and gentlemen. Click away."
		}, {
			name: "ctuser",
			content: [
				"This package includes a model, a request handler, and frontend components, including a profile page and a browsing interface, for handling user accounts.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctuser", "biggest p30 right")
			]
		}, {
			name: "ctblog",
			content: [
				"This package contains a generic blog-type website.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctblog", "biggest p30 right")
			]
		}, {
			name: "ctstore",
			content: [
				"This package enables the developer to create a basic ecommerce website with nothing but configuration.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctstore", "biggest p30 right")
			]
		}, {
			name: "ctdecide",
			content: [
				"This package provides a framework for group decision making.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctdecide", "biggest p30 right")
			]
		}, {
			name: "ctcoop",
			content: [
				"This package provides organizational management tools (in the form of web pages and components) for a cooperative.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctcoop", "biggest p30 right")
			]
		}, {
			name: "ctunes",
			content: [
				"This package contains a generic music website.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctunes", "biggest p30 right")
			]
		}, {
			name: "ctdocs",
			content: [
				"This package parses JSON-defined documentation data and displays it in a web page.",
				CT.dom.link("Code", null, "https://github.com/bubbleboy14/ctdocs", "biggest p30 right")
			]
		}
	], builder));
	CT.dom.setContent("ctmain", [content, clist]);
	var hash = location.hash.slice(1);
	if (hash)
		CT.dom.id("tl" + hash).trigger();
	else
		CT.dom.className("tlitem")[0].trigger();
});<|endoftext|>


<commit_before>Modules.VERSION = '1.0.1';
Modules.UTILS = true;

// PrefPanes - handles the preferences tab and all its contents for the add-on
// register(aPane, aModule) - registers a new preferences pane to be appended to the preferences tab
//	aPane - (str) name of the pane, in the form of a aPane.xul overlay to be found in content/
//	(optional) aModule -	(str) name of a module to be loaded alongside the overlay, in the form of a aModule.jsm to be found in resource/modules/;
//				if (bool) true, default to aPane
// unregister(aPane) - unregisters a preferences pane from the preferences tab
//	see register()
// setList(list) - register a set of panes at once
//	list - (iterable) list of arguments to apply to register()
// open() - tries to switch to an already opened add-on preferences tab; if none is found then a new one is opened in the most recent window
// closeAll() - closes all the add-on's preferences tab
this.PrefPanes = {
	chromeUri: 'chrome://'+objPathString+'/content/utils/preferences.xul',
	aboutUri: null,

	get notifyUri () {
		return (this.aboutUri ? this.aboutUri.spec : this.chromeUri) + '#paneAbout';
	},

	panes: new Map(),
	previousVersion: null,

	observe: function(aSubject, aTopic, aData) {
		this.initWindow(aSubject);
	},

	register: function(aPane, aModule) {
		if(!this.panes.has(aPane)) {
			this.panes.set(aPane, {
				module: (aModule === true) ? aPane : aModule
			});
		}
	},

	unregister: function(aPane) {
		if(this.panes.has(aPane)) {
			this.panes.delete(aPane);
		}
	},

	setList: function(list) {
		for(let args of list) {
			this.register.apply(this, args);
		}
	},

	init: function() {
		// we set the add-on status in the API webpage from within the add-on itself
		Messenger.loadInAll('utils/api');

		// always add the about pane to the preferences dialog, it should be the last category in the list
		this.register('utils/about', true);

		Browsers.callOnAll(aWindow => { this.initWindow(aWindow); }, this.chromeUri);
		Browsers.register(this, 'pageshow', this.chromeUri);

		// if defaults.js supplies an addonUUID, use it to register the about: uri linking to the add-on's preferences
		if(addonUUID) {
			this.aboutUri = {
				spec: 'about:'+objPathString,
				manager: Cm.QueryInterface(Ci.nsIComponentRegistrar),

				handler: {
					uri: Services.io.newURI(this.chromeUri, null, null),
					classDescription: 'about: handler for add-on '+objName,
					classID: Components.ID(addonUUID),
					contractID: '@mozilla.org/network/protocol/about;1?what='+objPathString,
					QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
					newChannel: function(aURI) {
						let chan = Services.io.newChannelFromURI(this.uri);
						chan.originalURI = aURI;
						return chan;
					},
					getURIFlags: function(aURI) 0
				},

				load: function() {
					this.manager.registerFactory(this.handler.classID, this.handler.classDescription, this.handler.contractID, this);
				},

				unload: function() {
					this.manager.unregisterFactory(this.handler.classID, this);
				},

				createInstance: function(outer, iid) {
					if(outer) {
						throw Cr.NS_ERROR_NO_AGGREGATION;
					}
					return this.handler;
				}
			};
			this.aboutUri.load();

			Browsers.callOnAll(aWindow => { this.initWindow(aWindow); }, this.aboutUri.spec);
			Browsers.register(this, 'pageshow', this.aboutUri.spec);
		}

		// if we're in a dev version, ignore all this
		if(AddonData.version.contains('a') || AddonData.version.contains('b')) { return; }

		// if we're updating from a version without this module, try to figure out the last version
		if(Prefs.lastVersionNotify == '0' && STARTED == ADDON_UPGRADE && AddonData.oldVersion) {
			Prefs.lastVersionNotify = AddonData.oldVersion;
		}

		// now make sure we notify the user when updating only; when installing for the first time do nothing
		if(Prefs.showTabOnUpdates && Prefs.lastVersionNotify != '0' && Services.vc.compare(Prefs.lastVersionNotify, AddonData.version) < 0) {
			this.previousVersion = Prefs.lastVersionNotify;
			this.openWhenReady();
		}

		// always set the pref to the current version, this also ensures only one notification tab will open per firefox session (and not one per window)
		if(Prefs.lastVersionNotify != AddonData.version) {
			Prefs.lastVersionNotify = AddonData.version;
		}

		// current version of firefox has some display issues, this doesn't seem needed in the current Nightly (FF41+)
		if(Services.vc.compare(Services.appinfo.version, '41.0a1') < 0) {
			var sscode = '@namespace url(http://www.w3.org/1999/xhtml);\n';
			sscode += '@-moz-document url("'+this.chromeUri+'")'+(this.aboutUri ? ', url("'+this.aboutUri.spec+'")' : '')+' {\n';
			sscode += '	#bank .hours { height: 100%; }\n';
			sscode += '	#bank .balance { position: relative; height: 50%; top: 0.4em; }\n';
			sscode += '}';
			LOG(sscode);
			Styles.load('PrefPanesFix', sscode, true);
		}
	},

	uninit: function() {
		Styles.unload('PrefPanesFix');

		Messenger.unloadFromAll('utils/api');

		this.closeAll();

		Browsers.unregister(this, 'pageshow', this.chromeUri);

		if(this.aboutUri) {
			Browsers.unregister(this, 'pageshow', this.aboutUri.spec);
			this.aboutUri.unload();
		}
	},

	// we have to wait for Session Store to finish, otherwise our tab will be overriden by a session-restored tab
	openWhenReady: function() {
		if(typeof(PrefPanes) == 'undefined') { return; }

		var aWindow = window; // most recent window, if it doesn't exist yet it means we're still starting up, so give it a second
		if(!aWindow || !aWindow.SessionStore) {
			aSync(() => { this.openWhenReady(); }, 500);
			return;
		}

		var state = JSON.parse(aWindow.SessionStore.getBrowserState());
		// we're in a window, so "a" window should exist...
		if(state.windows.length == 0) {
			aSync(() => { this.openWhenReady(); }, 500);
			return;
		}

		this.open(aWindow, true);
	},

	open: function(aWindow, loadOnStartup) {
		// first try to switch to an already opened options tab
		for(let tab of aWindow.gBrowser.mTabs) {
			if(tab.linkedBrowser.currentURI.spec.startsWith(this.chromeUri)
			|| (this.aboutUri && tab.linkedBrowser.currentURI.spec.startsWith(this.aboutUri.spec))) {
				aWindow.gBrowser.selectedTab = tab;
				return;
			}
		}

		// no tab was found, so open a new one
		if(loadOnStartup) {
			aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(this.notifyUri);
			aWindow.gBrowser.selectedTab.loadOnStartup = true; // for Tab Mix Plus
		}
		else {
			aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(this.aboutUri ? this.aboutUri.spec : this.chromeUri);
		}
	},

	closeAll: function() {
		Windows.callOnAll(aWindow => {
			for(let tab of aWindow.gBrowser.mTabs) {
				if(tab.linkedBrowser.currentURI.spec.startsWith(this.chromeUri)
				|| (this.aboutUri && tab.linkedBrowser.currentURI.spec.startsWith(this.aboutUri.spec))) {
					aWindow.gBrowser.removeTab(tab);
				}
			}
		}, 'navigator:browser');
	},

	initWindow: function(aWindow) {
		// prepare the window as usual
		replaceObjStrings(aWindow.document);
		prepareObject(aWindow, objName);

		// load the utils only when the preferences tab is finished with its overlays from this object
		let promises = [];
		for(let pane of this.panes.keys()) {
			promises.push(new Promise(function(resolve, reject) {
				let overlay = pane;
				Overlays.overlayWindow(aWindow, overlay, {
					onLoad: function() {
						resolve();
					}
				});
			}));
		}

		Promise.all(promises).then(() => {
			aWindow[objName].Modules.load("utils/preferencesUtils");

			// if any of the panes require their own module, load it now
			for(let pane of this.panes.values()) {
				if(pane.module) {
					aWindow[objName].Modules.load(pane.module);
				}
			}
		});
	}
};

Modules.LOADMODULE = function() {
	Prefs.setDefaults({
		lastPrefPane: '',
		lastVersionNotify: '0',
		showTabOnUpdates: true
	});

	PrefPanes.init();
};

Modules.UNLOADMODULE = function() {
	PrefPanes.uninit();
};
<commit_msg>cleanup<commit_after>Modules.VERSION = '1.0.1';
Modules.UTILS = true;

// PrefPanes - handles the preferences tab and all its contents for the add-on
// register(aPane, aModule) - registers a new preferences pane to be appended to the preferences tab
//	aPane - (str) name of the pane, in the form of a aPane.xul overlay to be found in content/
//	(optional) aModule -	(str) name of a module to be loaded alongside the overlay, in the form of a aModule.jsm to be found in resource/modules/;
//				if (bool) true, default to aPane
// unregister(aPane) - unregisters a preferences pane from the preferences tab
//	see register()
// setList(list) - register a set of panes at once
//	list - (iterable) list of arguments to apply to register()
// open() - tries to switch to an already opened add-on preferences tab; if none is found then a new one is opened in the most recent window
// closeAll() - closes all the add-on's preferences tab
this.PrefPanes = {
	chromeUri: 'chrome://'+objPathString+'/content/utils/preferences.xul',
	aboutUri: null,

	get notifyUri () {
		return (this.aboutUri ? this.aboutUri.spec : this.chromeUri) + '#paneAbout';
	},

	panes: new Map(),
	previousVersion: null,

	observe: function(aSubject, aTopic, aData) {
		this.initWindow(aSubject);
	},

	register: function(aPane, aModule) {
		if(!this.panes.has(aPane)) {
			this.panes.set(aPane, {
				module: (aModule === true) ? aPane : aModule
			});
		}
	},

	unregister: function(aPane) {
		if(this.panes.has(aPane)) {
			this.panes.delete(aPane);
		}
	},

	setList: function(list) {
		for(let args of list) {
			this.register.apply(this, args);
		}
	},

	init: function() {
		// we set the add-on status in the API webpage from within the add-on itself
		Messenger.loadInAll('utils/api');

		// always add the about pane to the preferences dialog, it should be the last category in the list
		this.register('utils/about', true);

		Browsers.callOnAll(aWindow => { this.initWindow(aWindow); }, this.chromeUri);
		Browsers.register(this, 'pageshow', this.chromeUri);

		// if defaults.js supplies an addonUUID, use it to register the about: uri linking to the add-on's preferences
		if(addonUUID) {
			this.aboutUri = {
				spec: 'about:'+objPathString,
				manager: Cm.QueryInterface(Ci.nsIComponentRegistrar),

				handler: {
					uri: Services.io.newURI(this.chromeUri, null, null),
					classDescription: 'about: handler for add-on '+objName,
					classID: Components.ID(addonUUID),
					contractID: '@mozilla.org/network/protocol/about;1?what='+objPathString,
					QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutModule]),
					newChannel: function(aURI) {
						let chan = Services.io.newChannelFromURI(this.uri);
						chan.originalURI = aURI;
						return chan;
					},
					getURIFlags: function(aURI) 0
				},

				load: function() {
					this.manager.registerFactory(this.handler.classID, this.handler.classDescription, this.handler.contractID, this);
				},

				unload: function() {
					this.manager.unregisterFactory(this.handler.classID, this);
				},

				createInstance: function(outer, iid) {
					if(outer) {
						throw Cr.NS_ERROR_NO_AGGREGATION;
					}
					return this.handler;
				}
			};
			this.aboutUri.load();

			Browsers.callOnAll(aWindow => { this.initWindow(aWindow); }, this.aboutUri.spec);
			Browsers.register(this, 'pageshow', this.aboutUri.spec);
		}

		// if we're in a dev version, ignore all this
		if(AddonData.version.contains('a') || AddonData.version.contains('b')) { return; }

		// if we're updating from a version without this module, try to figure out the last version
		if(Prefs.lastVersionNotify == '0' && STARTED == ADDON_UPGRADE && AddonData.oldVersion) {
			Prefs.lastVersionNotify = AddonData.oldVersion;
		}

		// now make sure we notify the user when updating only; when installing for the first time do nothing
		if(Prefs.showTabOnUpdates && Prefs.lastVersionNotify != '0' && Services.vc.compare(Prefs.lastVersionNotify, AddonData.version) < 0) {
			this.previousVersion = Prefs.lastVersionNotify;
			this.openWhenReady();
		}

		// always set the pref to the current version, this also ensures only one notification tab will open per firefox session (and not one per window)
		if(Prefs.lastVersionNotify != AddonData.version) {
			Prefs.lastVersionNotify = AddonData.version;
		}

		// current version of firefox has some display issues, this doesn't seem needed in the current Nightly (FF41+)
		if(Services.vc.compare(Services.appinfo.version, '41.0a1') < 0) {
			var sscode = '@namespace url(http://www.w3.org/1999/xhtml);\n';
			sscode += '@-moz-document url("'+this.chromeUri+'")'+(this.aboutUri ? ', url("'+this.aboutUri.spec+'")' : '')+' {\n';
			sscode += '	#bank .hours { height: 100%; }\n';
			sscode += '	#bank .balance { position: relative; height: 50%; top: 0.4em; }\n';
			sscode += '}';

			Styles.load('PrefPanesFix', sscode, true);
		}
	},

	uninit: function() {
		Styles.unload('PrefPanesFix');

		Messenger.unloadFromAll('utils/api');

		this.closeAll();

		Browsers.unregister(this, 'pageshow', this.chromeUri);

		if(this.aboutUri) {
			Browsers.unregister(this, 'pageshow', this.aboutUri.spec);
			this.aboutUri.unload();
		}
	},

	// we have to wait for Session Store to finish, otherwise our tab will be overriden by a session-restored tab
	openWhenReady: function() {
		if(typeof(PrefPanes) == 'undefined') { return; }

		var aWindow = window; // most recent window, if it doesn't exist yet it means we're still starting up, so give it a second
		if(!aWindow || !aWindow.SessionStore) {
			aSync(() => { this.openWhenReady(); }, 500);
			return;
		}

		var state = JSON.parse(aWindow.SessionStore.getBrowserState());
		// we're in a window, so "a" window should exist...
		if(state.windows.length == 0) {
			aSync(() => { this.openWhenReady(); }, 500);
			return;
		}

		this.open(aWindow, true);
	},

	open: function(aWindow, loadOnStartup) {
		// first try to switch to an already opened options tab
		for(let tab of aWindow.gBrowser.mTabs) {
			if(tab.linkedBrowser.currentURI.spec.startsWith(this.chromeUri)
			|| (this.aboutUri && tab.linkedBrowser.currentURI.spec.startsWith(this.aboutUri.spec))) {
				aWindow.gBrowser.selectedTab = tab;
				return;
			}
		}

		// no tab was found, so open a new one
		if(loadOnStartup) {
			aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(this.notifyUri);
			aWindow.gBrowser.selectedTab.loadOnStartup = true; // for Tab Mix Plus
		}
		else {
			aWindow.gBrowser.selectedTab = aWindow.gBrowser.addTab(this.aboutUri ? this.aboutUri.spec : this.chromeUri);
		}
	},

	closeAll: function() {
		Windows.callOnAll(aWindow => {
			for(let tab of aWindow.gBrowser.mTabs) {
				if(tab.linkedBrowser.currentURI.spec.startsWith(this.chromeUri)
				|| (this.aboutUri && tab.linkedBrowser.currentURI.spec.startsWith(this.aboutUri.spec))) {
					aWindow.gBrowser.removeTab(tab);
				}
			}
		}, 'navigator:browser');
	},

	initWindow: function(aWindow) {
		// prepare the window as usual
		replaceObjStrings(aWindow.document);
		prepareObject(aWindow, objName);

		// load the utils only when the preferences tab is finished with its overlays from this object
		let promises = [];
		for(let pane of this.panes.keys()) {
			promises.push(new Promise(function(resolve, reject) {
				let overlay = pane;
				Overlays.overlayWindow(aWindow, overlay, {
					onLoad: function() {
						resolve();
					}
				});
			}));
		}

		Promise.all(promises).then(() => {
			aWindow[objName].Modules.load("utils/preferencesUtils");

			// if any of the panes require their own module, load it now
			for(let pane of this.panes.values()) {
				if(pane.module) {
					aWindow[objName].Modules.load(pane.module);
				}
			}
		});
	}
};

Modules.LOADMODULE = function() {
	Prefs.setDefaults({
		lastPrefPane: '',
		lastVersionNotify: '0',
		showTabOnUpdates: true
	});

	PrefPanes.init();
};

Modules.UNLOADMODULE = function() {
	PrefPanes.uninit();
};
<|endoftext|>


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

  // Triggers on pages with install button
  if (!$('#installButton').length)
    return;

  // Check if extension is installed by sending a message via Chrome runtime
  if (typeof chrome !== 'undefined' && chrome.runtime) {
    chrome.runtime.sendMessage('hlkhpekhgcaigleojiocoeockhcaglia', {
        message: 'version'
      },
      reply => {
        if (reply) {
          if (cmp(reply.version, "0.1.0") == -1) {
            $('#extensionMessage').html(' Update available');
            $('#extensionMessage').fadeIn();
            $('#installButton').fadeOut(400, () => {
              $('#installButton').val('Update now »');
            });
            $('#installButton').fadeIn(200);
          } else {
            $('#installButton').attr('disabled', 'disabled');
            $('#extensionMessage').html(' Installed!');
            $('#extensionMessage').fadeIn();
          }
        }
      });
    $('#installButton').click(() => {
      chrome.webstore.install(undefined, // no URL needed, specified in HTML head
        () => {
          $('#installButton').attr('disabled', 'disabled');
          $('#extensionMessage').html(' Successfully installed!');
          $('#extensionMessage').fadeIn();
        },
        (error) => {
          window.location = 'https://chrome.google.com/webstore/detail/free-your-stuff/hlkhpekhgcaigleojiocoeockhcaglia';
        });
    });
  } else {
    $('#installButton').click(() => {
      $('#extensionMessage').html('  This browser extension requires Chrome or Chromium.');
      $('#extensionMessage').fadeIn();
    });
  }
})();

// semver-compare, from https://github.com/substack/semver-compare - MIT License
function cmp(a, b) {
  var pa = a.split('.');
  var pb = b.split('.');
  for (var i = 0; i < 3; i++) {
    var na = Number(pa[i]);
    var nb = Number(pb[i]);
    if (na > nb) return 1;
    if (nb > na) return -1;
    if (!isNaN(na) && isNaN(nb)) return 1;
    if (isNaN(na) && !isNaN(nb)) return -1;
  }
  return 0;
}
<commit_msg>Inline install no longer supported, remove<commit_after>'use strict';
(function() {

  // Triggers on pages with install button
  if (!$('#installButton').length)
    return;

  // Check if extension is installed by sending a message via Chrome runtime
  if (typeof chrome !== 'undefined' && chrome.runtime) {
    chrome.runtime.sendMessage('hlkhpekhgcaigleojiocoeockhcaglia', {
        message: 'version'
      },
      reply => {
        if (reply) {
          if (cmp(reply.version, "0.1.0") == -1) {
            $('#extensionMessage').html(' Update available');
            $('#extensionMessage').fadeIn();
            $('#installButton').fadeOut(400, () => {
              $('#installButton').val('Update now »');
            });
            $('#installButton').fadeIn(200);
          } else {
            $('#installButton').attr('disabled', 'disabled');
            $('#extensionMessage').html(' Installed!');
            $('#extensionMessage').fadeIn();
          }
        }
      });
    $('#installButton').click(() => {
      window.location = 'https://chrome.google.com/webstore/detail/free-your-stuff/hlkhpekhgcaigleojiocoeockhcaglia';
    });
  } else {
    $('#installButton').click(() => {
      $('#extensionMessage').html('  This browser extension requires Chrome or Chromium.');
      $('#extensionMessage').fadeIn();
    });
  }
})();

// semver-compare, from https://github.com/substack/semver-compare - MIT License
function cmp(a, b) {
  var pa = a.split('.');
  var pb = b.split('.');
  for (var i = 0; i < 3; i++) {
    var na = Number(pa[i]);
    var nb = Number(pb[i]);
    if (na > nb) return 1;
    if (nb > na) return -1;
    if (!isNaN(na) && isNaN(nb)) return 1;
    if (isNaN(na) && !isNaN(nb)) return -1;
  }
  return 0;
}
<|endoftext|>


<commit_before>'use strict';

var categoryMenu = require('../services/response/categoryMenuResponse').getInstance();
var productMenu = require('../services/response/productMenuResponse').getInstance();
var checkoutMenu = require('../services/response/checkoutResponse').getInstance();
var orderMenu = require('../services/response/orderResponse').getInstance();

const MENU = 'menu';
const ALL = 'all';
const CATEGORY = 'category';
const PRODUCT = 'product';
const ORDER_PRODUCT = 'order';

function ResponseFactory() {
}

ResponseFactory.prototype = {
    getResponse: function (message) {
        var messages = message.split('#');
        var data = messages[1] !== undefined ? messages[1] : null;
        var type = messages[0] !== undefined ? messages[0] : null;

        console.info("type ", type);
        console.info("id ", data);

        switch (type) {
            case MENU:
                break;
            case ALL:
                console.info("step:", ALL)
                return categoryMenu.getResponse();
                break;
            case CATEGORY:
                return productMenu.getResponse();
                break;
            case PRODUCT:
                console.log("GOT PRODUCT!");
                return checkoutMenu.getResponse(data[0]);
                break;
            case ORDER_PRODUCT:
                return orderMenu.getResponse(data[0]);
                break;
        }
    }
};

/**
 * @returns {ResponseFactory}
 */
module.exports.getInstance = function () {
    return new ResponseFactory();
};
<commit_msg>change categories url<commit_after>'use strict';

var categoryMenu = require('../services/response/categoryMenuResponse').getInstance();
var productMenu = require('../services/response/productMenuResponse').getInstance();
var checkoutMenu = require('../services/response/checkoutResponse').getInstance();
var orderMenu = require('../services/response/orderResponse').getInstance();

const MENU = 'menu';
const ALL = 'all';
const CATEGORY = 'category';
const PRODUCT = 'product';
const ORDER_PRODUCT = 'order';

function ResponseFactory() {
}

ResponseFactory.prototype = {
    getResponse: function (message) {
        var messages = message.split('#');
        var data = messages[1] !== undefined ? messages[1] : null;
        var type = messages[0] !== undefined ? messages[0] : null;

        console.info("type ", type);
        console.info("id ", data);

        switch (type) {
            case MENU:
                break;
            case ALL:
                console.info("step:", ALL);
                return categoryMenu.getResponse();
                break;
            case CATEGORY:
                return productMenu.getResponse();
                break;
            case PRODUCT:
                console.log("GOT PRODUCT!");
                return checkoutMenu.getResponse(data[0]);
                break;
            case ORDER_PRODUCT:
                return orderMenu.getResponse(data[0]);
                break;
        }
    }
};

/**
 * @returns {ResponseFactory}
 */
module.exports.getInstance = function () {
    return new ResponseFactory();
};
<|endoftext|>


<commit_before>'use strict';

var five = require('johnny-five'),
		Raspi = require('raspi-io');
var sys = require('sys')
var exec = require('child_process').exec;
var child;
var on = true;
var rightServo, leftServo;

var board = new five.Board({
	io: new Raspi()
});

board.on('ready', function () {
	rightServo = new five.Servo.Continuous('GPIO18');
	leftServo = new five.Servo.Continuous('GPIO19');
	this.repl.inject({
		right: rightServo,
		left: leftServo,
	});
});
module.exports.forward = function() {
	rightServo.cw(1);
	leftServo.ccw(1);
}
module.exports.backward = function() {
	rightServo.ccw(1);
	leftServo.cw(1);
}
module.exports.left = function() {
	rightServo.ccw(1);
	leftServo.ccw(1);
}
module.exports.right = function() {
	rightServo.cw(1);
	leftServo.cw(1);
}
module.exports.stop = function() {
	rightServo.stop();
	leftServo.stop();
}
<commit_msg>turning the wrong direction<commit_after>'use strict';

var five = require('johnny-five'),
		Raspi = require('raspi-io');
var sys = require('sys')
var exec = require('child_process').exec;
var child;
var on = true;
var rightServo, leftServo;

var board = new five.Board({
	io: new Raspi()
});

board.on('ready', function () {
	rightServo = new five.Servo.Continuous('GPIO18');
	leftServo = new five.Servo.Continuous('GPIO19');
	this.repl.inject({
		right: rightServo,
		left: leftServo,
	});
});
module.exports.forward = function() {
	rightServo.cw(1);
	leftServo.ccw(1);
}
module.exports.backward = function() {
	rightServo.ccw(1);
	leftServo.cw(1);
}
module.exports.left = function() {
	rightServo.cw(1);
	leftServo.cw(1);
}
module.exports.right = function() {
	rightServo.ccw(1);
	leftServo.ccw(1);
}
module.exports.stop = function() {
	rightServo.stop();
	leftServo.stop();
}
<|endoftext|>


<commit_before>// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

import Log from './Log';

const CheckForPopupClosedInterval = 500;

export default class PopupWindow {

    constructor() {
        Log.info("PopupWindow.ctor");

        this._promise = new Promise((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });

        this._boundMessageEvent = this._message.bind(this);
        window.addEventListener("message", this._boundMessageEvent, false);

        this._popup = window.open('', '_blank', 'location=no,toolbar=no,width=500,height=500');
        if (this._popup) {
            Log.info("popup successfully created");
            this._checkForPopupClosedTimer = window.setInterval(this._checkForPopupClosed.bind(this), CheckForPopupClosedInterval);
        }
    }

    navigate(params) {
        Log.info("PopupWindow.navigate");

        if (!this._popup) {
            this._error("Error opening popup window");
        }
        else if (!params || !params.url) {
            this._error("No url provided");
        }
        else {
            Log.info("Setting URL in popup");

            this._popup.focus();
            this._popup.window.location = params.url;
        }

        return this.promise;
    }

    get promise() {
        return this._promise;
    }

    _success(data) {
        this._cleanup();

        Log.info("Successful response from popup window");
        this._resolve(data);
    }
    _error(message) {
        this._cleanup();

        Log.error(message);
        this._reject(new Error(message));
    }

    _cleanup() {
        Log.info("PopupWindow._cleanup");

        window.removeEventListener("message", this._boundMessageEvent, false);
        window.clearInterval(this._checkForPopupClosedTimer);

        this._checkForPopupClosedTimer = null;
        this._boundMessageEventssage = null;
        this._popup = null;
    }

    _checkForPopupClosed() {
        Log.info("PopupWindow._checkForPopupClosed");

        if (!this._popup.window) {
            this._error("Popup window closed");
        }
    }

    _message(e) {
        Log.info("PopupWindow._message");

        if (e.origin === this._origin &&
            e.source === this._popup.window
        ) {
            Log.info("processing message");

            let url = e.data.url;

            this._cleanup();

            if (url) {
                this._success({ url: url });
            }
            else {
                this._error("Invalid response from popup");
            }
        }
    }

    get _origin() {
        return location.protocol + "//" + location.host;
    }

    static notifyOpener(url) {
        Log.info("PopupWindow.notifyOpener");

        if (window.opener) {
            url = url || window.location.href;
            if (url) {
                Log.info("posting url message to opener");

                window.opener.postMessage({ url: url }, location.protocol + "//" + location.host);
                window.close();
            }
        }
    }
}
<commit_msg>check closed flag on window for popup cleanup<commit_after>// Copyright (c) Brock Allen & Dominick Baier. All rights reserved.
// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information.

import Log from './Log';

const CheckForPopupClosedInterval = 500;

export default class PopupWindow {

    constructor() {
        Log.info("PopupWindow.ctor");

        this._promise = new Promise((resolve, reject) => {
            this._resolve = resolve;
            this._reject = reject;
        });

        this._boundMessageEvent = this._message.bind(this);
        window.addEventListener("message", this._boundMessageEvent, false);

        this._popup = window.open('', '_blank', 'location=no,toolbar=no,width=500,height=500');
        if (this._popup) {
            Log.info("popup successfully created");
            this._checkForPopupClosedTimer = window.setInterval(this._checkForPopupClosed.bind(this), CheckForPopupClosedInterval);
        }
    }

    navigate(params) {
        Log.info("PopupWindow.navigate");

        if (!this._popup) {
            this._error("Error opening popup window");
        }
        else if (!params || !params.url) {
            this._error("No url provided");
        }
        else {
            Log.info("Setting URL in popup");

            this._popup.focus();
            this._popup.window.location = params.url;
        }

        return this.promise;
    }

    get promise() {
        return this._promise;
    }

    _success(data) {
        this._cleanup();

        Log.info("Successful response from popup window");
        this._resolve(data);
    }
    _error(message) {
        this._cleanup();

        Log.error(message);
        this._reject(new Error(message));
    }

    _cleanup() {
        Log.info("PopupWindow._cleanup");

        window.removeEventListener("message", this._boundMessageEvent, false);
        window.clearInterval(this._checkForPopupClosedTimer);

        this._checkForPopupClosedTimer = null;
        this._boundMessageEventssage = null;
        this._popup = null;
    }

    _checkForPopupClosed() {
        Log.info("PopupWindow._checkForPopupClosed");

        if (!this._popup || !this._popup.window || this._popup.closed) {
            this._error("Popup window closed");
        }
    }

    _message(e) {
        Log.info("PopupWindow._message");

        if (e.origin === this._origin &&
            e.source === this._popup.window
        ) {
            Log.info("processing message");

            let url = e.data.url;

            this._cleanup();

            if (url) {
                this._success({ url: url });
            }
            else {
                this._error("Invalid response from popup");
            }
        }
    }

    get _origin() {
        return location.protocol + "//" + location.host;
    }

    static notifyOpener(url) {
        Log.info("PopupWindow.notifyOpener");

        if (window.opener) {
            url = url || window.location.href;
            if (url) {
                Log.info("posting url message to opener");

                window.opener.postMessage({ url: url }, location.protocol + "//" + location.host);
                window.close();
            }
        }
    }
}
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { findDOMNode } from 'react-dom'
import Dropdown from './Dropdown'
import SelectTrigger from './SelectTrigger'
import DropdownMenu from './DropdownMenu'
import SelectedOption from './SelectedOption'
import BeforeOptions from './BeforeOptions'
import AfterOptions from './AfterOptions'
import { matcher } from './utils'

const KEYCODES = {
  UP_ARROW: 38,
  DOWN_ARROW: 40,
  ENTER: 13,
  TAB: 9
}

const actions = {
  38: 'handleUpArrow',
  40: 'handleDownArrow',
  13: 'handleEnterPress',
  9: 'handleTabPress'
}

const noop = () => {}

export default class PowerSelect extends Component {
  documentEventListeners = {
    handleEscapePress: ::this.handleEscapePress,
    handleDocumentClick: ::this.handleDocumentClick
  }

  select = {
    open: ::this.open,
    close: ::this.close,
    toggle: ::this.toggle,
    search: ::this.search,
  }

  constructor() {
    super(...arguments)
    this.state = {
      highlightedIndex: null,
      isOpen: false,
      focused: false,
      filteredOptions: null,
      searchTerm: null
    }

    this.open = ::this.open
    this.close = ::this.close
    this.toggle = ::this.toggle
    this.selectOption = ::this.selectOption
    this.handleOptionClick = ::this.handleOptionClick
    this.handleKeyDown = ::this.handleKeyDown
    this.handleTriggerChange = ::this.handleTriggerChange
    this.handleFocus = ::this.handleFocus
    this.handleBlur = ::this.handleBlur
    this.handleClick = ::this.handleClick
  }

  componentDidMount() {
    document.addEventListener('keydown', this.documentEventListeners.handleEscapePress)
    document.addEventListener('click', this.documentEventListeners.handleDocumentClick)
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this.documentEventListeners.handleEscapePress)
    document.removeEventListener('click', this.documentEventListeners.handleDocumentClick)
  }

  highlightOption(highlightedIndex) {
    this.setState({
      highlightedIndex
    })
  }

  selectOption(highlightedIndex, option) {
    let options = this.state.filteredOptions || this.props.options
    let selectedOption = option || options[highlightedIndex]
    this.highlightOption(highlightedIndex)
    this.props.onChange(selectedOption, this.select)
    this.setState({
      searchTerm: null
    })
  }

  open() {
    if (this.props.disabled) {
      return
    }

    let highlightedIndex = this.state.highlightedIndex
    let { options, selected } = this.props
    highlightedIndex = highlightedIndex !== null ? highlightedIndex : options.indexOf(selected)

    this.highlightOption(highlightedIndex)
    this.setState({
      isOpen: true,
    })
  }

  close() {
    this.highlightOption(null)
    this.setState({
      isOpen: false,
      filteredOptions: null,
    })
  }

  toggle(event) {
    event && event.stopPropagation()
    if (this.state.isOpen) {
      this.close()
    } else {
      this.open()
    }
  }

  setFocusedState(focused) {
    this.setState({ focused })
  }

  focusField() {
    findDOMNode(this.refs['powerselect-trigger-container']).focus()
  }

  search(searchTerm, callback) {
    let { options, searchIndices } = this.props
    let filteredOptions = options.filter((option) => {
      return this.props.matcher({
        option,
        searchTerm,
        searchIndices
      })
    })

    if (!searchTerm || !filteredOptions.length) {
      let highlightedIndex = -1
      this.highlightOption(highlightedIndex)
    }

    this.setState({
      filteredOptions,
      searchTerm,
    }, callback)
  }

  handleTriggerChange(event) {
    let value = event.target.value
    this.search(value, this.open)
  }

  handleDownArrow(index) {
    let options = this.state.filteredOptions || this.props.options
    let highlightedIndex = index < options.length - 1 ? ++index : 0
    this.highlightOption(highlightedIndex)
  }

  handleUpArrow(index) {
    let options = this.state.filteredOptions || this.props.options
    let highlightedIndex = (index > 0 && index <= options.length) ? --index : options.length - 1
    this.highlightOption(highlightedIndex)
  }

  handleEnterPress(highlightedIndex) {
    if (this.state.isOpen) {
      this.selectOption(highlightedIndex)
      this.focusField()
      this.close()
    }
    if (highlightedIndex === -1) {
      this.props.onEnter(this.getPublicApi())
    }
  }

  handleTabPress(highlightedIndex) {
    this.setFocusedState(false)
    if (this.state.isOpen) {
      this.selectOption(highlightedIndex)
      this.close()
    }
  }

  handleKeyDown(event, highlightedIndex) {
    let keyCode = event.which
    let action = this[actions[keyCode]]
    if (action) {
      if ((keyCode === KEYCODES.UP_ARROW || keyCode === KEYCODES.DOWN_ARROW) && !this.state.isOpen) {
        this.open()
        return
      }

      action.call(this, highlightedIndex)
    }
  }

  handleEscapePress(event) {
    if (event.which === 27) {
      this.close()
    }
  }

  handleDocumentClick(event) {
    let $target = event.target
    if (!($target.closest('.powerselect') || $target.closest('.powerselect__menu'))) {
      let { focused, isOpen } = this.state
      if (focused) {
        this.setFocusedState(false)
      }

      if (isOpen) {
        this.selectOption(this.state.highlightedIndex)
        this.close()
      }
    }
  }

  handleFocus(event) {
    this.setFocusedState(true)
    this.props.onFocus(event)
  }

  handleBlur(event) {
    this.setFocusedState(false)
    this.props.onBlur(event)
  }

  handleClick(event) {
    this.toggle(event)
    this.props.onClick(event)
  }

  handleOptionClick(option) {
    this.selectOption(option)
    this.focusField()
    this.close()
  }

  getPublicApi() {
    let { isOpen, searchTerm } = this.state

    return {
      ...this.select,
      isOpen,
      searchTerm,
    }
  }

  render() {
    let {
      className,
      options,
      selected,
      selectedLabel,
      placeholder,
      disabled,
      optionComponent,
      selectedOptionComponent,
      beforeOptionsComponent,
      afterOptionsComponent
    } = this.props

    let { isOpen } = this.state
    let filteredOptions = this.state.filteredOptions || options
    let SelectTrigger = this.props.selectTriggerComponent
    let selectApi = this.getPublicApi()
    let { highlightedIndex, focused } = this.state

    return (
      <Dropdown>
        <div
          ref='powerselect-trigger-container'
          className={
            `powerselect ${className} ${disabled ? 'powerselect--disabled' : ''} ${isOpen ? 'powerselect--open' : ''} ${focused ? 'powerselect--focused' : '' }`
          }
          tabIndex={0}
          onFocus={() => {
            let triggerContainer = findDOMNode(this.refs['powerselect-trigger-container'])
            let triggerInput = triggerContainer.querySelector('input')
            if (triggerInput) {
              triggerInput.focus()
            }
          }}
        >
          <SelectTrigger
            selectedOption={selected}
            selectedLabel={selectedLabel}
            selectedOptionComponent={selectedOptionComponent}
            placeholder={placeholder}
            disabled={disabled}
            handleKeyDown={(event) => {
              this.handleKeyDown(event, highlightedIndex)
            }}
            searchTerm={this.state.searchTerm}
            handleOnChange={this.handleTriggerChange}
            onClick={this.handleClick}
            handleOnFocus={this.handleFocus}
            handleOnBlur={this.handleBlur}
            select={selectApi}
          />
        </div>
        {
          isOpen &&
          <DropdownMenu
            minWidth={this.refs['powerselect-trigger-container'].offsetWidth}
            options={filteredOptions}
            selected={selected}
            optionComponent={optionComponent}
            onOptionClick={this.handleOptionClick}
            handleKeyDown={this.handleKeyDown}
            highlightedIndex={highlightedIndex}
            select={selectApi}
            beforeOptionsComponent={beforeOptionsComponent}
            afterOptionsComponent={afterOptionsComponent}
          />
        }
      </Dropdown>
    )
  }
}

PowerSelect.propTypes = {
  options: PropTypes.array.isRequired,
  selected: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  onChange: PropTypes.func.isRequired,
}

PowerSelect.defaultProps = {
  options: [],
  disabled: false,
  selectTriggerComponent: SelectTrigger,
  selectedOptionComponent: SelectedOption,
  beforeOptionsComponent: BeforeOptions,
  afterOptionsComponent: null,
  matcher: matcher,
  onFocus: noop,
  onBlur: noop,
  onClick: noop,
  onEnter: noop,
}
<commit_msg>Add  class to the root component<commit_after>import React, { Component, PropTypes } from 'react'
import { findDOMNode } from 'react-dom'
import Dropdown from './Dropdown'
import SelectTrigger from './SelectTrigger'
import DropdownMenu from './DropdownMenu'
import SelectedOption from './SelectedOption'
import BeforeOptions from './BeforeOptions'
import AfterOptions from './AfterOptions'
import { matcher } from './utils'

const KEYCODES = {
  UP_ARROW: 38,
  DOWN_ARROW: 40,
  ENTER: 13,
  TAB: 9
}

const actions = {
  38: 'handleUpArrow',
  40: 'handleDownArrow',
  13: 'handleEnterPress',
  9: 'handleTabPress'
}

const noop = () => {}

export default class PowerSelect extends Component {
  documentEventListeners = {
    handleEscapePress: ::this.handleEscapePress,
    handleDocumentClick: ::this.handleDocumentClick
  }

  select = {
    open: ::this.open,
    close: ::this.close,
    toggle: ::this.toggle,
    search: ::this.search,
  }

  constructor() {
    super(...arguments)
    this.state = {
      highlightedIndex: null,
      isOpen: false,
      focused: false,
      filteredOptions: null,
      searchTerm: null
    }

    this.open = ::this.open
    this.close = ::this.close
    this.toggle = ::this.toggle
    this.selectOption = ::this.selectOption
    this.handleOptionClick = ::this.handleOptionClick
    this.handleKeyDown = ::this.handleKeyDown
    this.handleTriggerChange = ::this.handleTriggerChange
    this.handleFocus = ::this.handleFocus
    this.handleBlur = ::this.handleBlur
    this.handleClick = ::this.handleClick
  }

  componentDidMount() {
    document.addEventListener('keydown', this.documentEventListeners.handleEscapePress)
    document.addEventListener('click', this.documentEventListeners.handleDocumentClick)
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this.documentEventListeners.handleEscapePress)
    document.removeEventListener('click', this.documentEventListeners.handleDocumentClick)
  }

  highlightOption(highlightedIndex) {
    this.setState({
      highlightedIndex
    })
  }

  selectOption(highlightedIndex, option) {
    let options = this.state.filteredOptions || this.props.options
    let selectedOption = option || options[highlightedIndex]
    this.highlightOption(highlightedIndex)
    this.props.onChange(selectedOption, this.select)
    this.setState({
      searchTerm: null
    })
  }

  open() {
    if (this.props.disabled) {
      return
    }

    let highlightedIndex = this.state.highlightedIndex
    let { options, selected } = this.props
    highlightedIndex = highlightedIndex !== null ? highlightedIndex : options.indexOf(selected)

    this.highlightOption(highlightedIndex)
    this.setState({
      isOpen: true,
    })
  }

  close() {
    this.highlightOption(null)
    this.setState({
      isOpen: false,
      filteredOptions: null,
    })
  }

  toggle(event) {
    event && event.stopPropagation()
    if (this.state.isOpen) {
      this.close()
    } else {
      this.open()
    }
  }

  setFocusedState(focused) {
    this.setState({ focused })
  }

  focusField() {
    findDOMNode(this.refs['powerselect-trigger-container']).focus()
  }

  search(searchTerm, callback) {
    let { options, searchIndices } = this.props
    let filteredOptions = options.filter((option) => {
      return this.props.matcher({
        option,
        searchTerm,
        searchIndices
      })
    })

    if (!searchTerm || !filteredOptions.length) {
      let highlightedIndex = -1
      this.highlightOption(highlightedIndex)
    }

    this.setState({
      filteredOptions,
      searchTerm,
    }, callback)
  }

  handleTriggerChange(event) {
    let value = event.target.value
    this.search(value, this.open)
  }

  handleDownArrow(index) {
    let options = this.state.filteredOptions || this.props.options
    let highlightedIndex = index < options.length - 1 ? ++index : 0
    this.highlightOption(highlightedIndex)
  }

  handleUpArrow(index) {
    let options = this.state.filteredOptions || this.props.options
    let highlightedIndex = (index > 0 && index <= options.length) ? --index : options.length - 1
    this.highlightOption(highlightedIndex)
  }

  handleEnterPress(highlightedIndex) {
    if (this.state.isOpen) {
      this.selectOption(highlightedIndex)
      this.focusField()
      this.close()
    }
    if (highlightedIndex === -1) {
      this.props.onEnter(this.getPublicApi())
    }
  }

  handleTabPress(highlightedIndex) {
    this.setFocusedState(false)
    if (this.state.isOpen) {
      this.selectOption(highlightedIndex)
      this.close()
    }
  }

  handleKeyDown(event, highlightedIndex) {
    let keyCode = event.which
    let action = this[actions[keyCode]]
    if (action) {
      if ((keyCode === KEYCODES.UP_ARROW || keyCode === KEYCODES.DOWN_ARROW) && !this.state.isOpen) {
        this.open()
        return
      }

      action.call(this, highlightedIndex)
    }
  }

  handleEscapePress(event) {
    if (event.which === 27) {
      this.close()
    }
  }

  handleDocumentClick(event) {
    let $target = event.target
    if (!($target.closest('.powerselect') || $target.closest('.powerselect__menu'))) {
      let { focused, isOpen } = this.state
      if (focused) {
        this.setFocusedState(false)
      }

      if (isOpen) {
        this.selectOption(this.state.highlightedIndex)
        this.close()
      }
    }
  }

  handleFocus(event) {
    this.setFocusedState(true)
    this.props.onFocus(event)
  }

  handleBlur(event) {
    this.setFocusedState(false)
    this.props.onBlur(event)
  }

  handleClick(event) {
    this.toggle(event)
    this.props.onClick(event)
  }

  handleOptionClick(option) {
    this.selectOption(option)
    this.focusField()
    this.close()
  }

  getPublicApi() {
    let { isOpen, searchTerm } = this.state

    return {
      ...this.select,
      isOpen,
      searchTerm,
    }
  }

  render() {
    let {
      className,
      options,
      selected,
      selectedLabel,
      placeholder,
      disabled,
      optionComponent,
      selectedOptionComponent,
      beforeOptionsComponent,
      afterOptionsComponent
    } = this.props

    let { isOpen, searchTerm } = this.state
    let filteredOptions = this.state.filteredOptions || options
    let SelectTrigger = this.props.selectTriggerComponent
    let selectApi = this.getPublicApi()
    let { highlightedIndex, focused } = this.state

    return (
      <Dropdown>
        <div
          ref='powerselect-trigger-container'
          className={
            `powerselect ${className} ${disabled ? 'powerselect--disabled' : ''} ${isOpen ? 'powerselect--open' : ''} ${focused ? 'powerselect--focused' : '' } ${searchTerm ? 'powerselect__with-search' : ''}`
          }
          tabIndex={0}
          onFocus={() => {
            let triggerContainer = findDOMNode(this.refs['powerselect-trigger-container'])
            let triggerInput = triggerContainer.querySelector('input')
            if (triggerInput) {
              triggerInput.focus()
            }
          }}
        >
          <SelectTrigger
            selectedOption={selected}
            selectedLabel={selectedLabel}
            selectedOptionComponent={selectedOptionComponent}
            placeholder={placeholder}
            disabled={disabled}
            handleKeyDown={(event) => {
              this.handleKeyDown(event, highlightedIndex)
            }}
            searchTerm={searchTerm}
            handleOnChange={this.handleTriggerChange}
            onClick={this.handleClick}
            handleOnFocus={this.handleFocus}
            handleOnBlur={this.handleBlur}
            select={selectApi}
          />
        </div>
        {
          isOpen &&
          <DropdownMenu
            minWidth={this.refs['powerselect-trigger-container'].offsetWidth}
            options={filteredOptions}
            selected={selected}
            optionComponent={optionComponent}
            onOptionClick={this.handleOptionClick}
            handleKeyDown={this.handleKeyDown}
            highlightedIndex={highlightedIndex}
            select={selectApi}
            beforeOptionsComponent={beforeOptionsComponent}
            afterOptionsComponent={afterOptionsComponent}
          />
        }
      </Dropdown>
    )
  }
}

PowerSelect.propTypes = {
  options: PropTypes.array.isRequired,
  selected: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.object
  ]),
  onChange: PropTypes.func.isRequired,
}

PowerSelect.defaultProps = {
  options: [],
  disabled: false,
  selectTriggerComponent: SelectTrigger,
  selectedOptionComponent: SelectedOption,
  beforeOptionsComponent: BeforeOptions,
  afterOptionsComponent: null,
  matcher: matcher,
  onFocus: noop,
  onBlur: noop,
  onClick: noop,
  onEnter: noop,
}
<|endoftext|>


<commit_before>XWikiObj(function (obj) {
    obj.setExpertFeedbackURL("");
    obj.setFeedbackURL("");
    obj.setOauthPublicKey("UI-dXouxI4J18UhIAXr-J0yK9H8");
    obj.setRdr("http://localhost:8080/riscoss-rdr");
});
<commit_msg>OAuth key should not be shipped with the software<commit_after>XWikiObj(function (obj) {
    obj.setExpertFeedbackURL("");
    obj.setFeedbackURL("");
    obj.setOauthPublicKey("");
    obj.setRdr("http://localhost:8080/riscoss-rdr");
});
<|endoftext|>