<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

import base64 from 'base-64';
import React from 'react';
import app from '../../../app';
import {json} from '../../../core/ajax';
import FauxtonAPI from '../../../core/api';
import {ReplicationSource} from './source';
import {ReplicationTarget} from './target';
import {ReplicationOptions} from './options';
import {ReplicationSubmit} from './submit';
import {ReplicationAuth} from './auth-options';
import Constants from '../constants';
import {ConflictModal} from './modals';
import {isEmpty} from 'lodash';

export default class NewReplicationController extends React.Component {
  constructor (props) {
    super(props);
    this.submit = this.submit.bind(this);
    this.checkAuth = this.checkAuth.bind(this);
    this.runReplicationChecks = this.runReplicationChecks.bind(this);
  }

  checkAuth () {
    this.props.hideConflictModal();
    const { replicationSource, replicationTarget,
      sourceAuthType, targetAuthType, sourceAuth, targetAuth } = this.props;

    const isLocalSource = replicationSource === Constants.REPLICATION_SOURCE.LOCAL;
    const isLocalTarget = replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE;

    // Ask user to select an auth method for local source/target when one is not selected
    // and not on admin party
    if (!FauxtonAPI.session.isAdminParty()) {
      if (isLocalSource && sourceAuthType === Constants.REPLICATION_AUTH_METHOD.NO_AUTH) {
        FauxtonAPI.addNotification({
          msg: 'Missing credentials for local source database.',
          type: 'error',
          clear: true
        });
        return;
      }
      if (isLocalTarget && targetAuthType === Constants.REPLICATION_AUTH_METHOD.NO_AUTH) {
        FauxtonAPI.addNotification({
          msg: 'Missing credentials for local target database.',
          type: 'error',
          clear: true
        });
        return;
      }
    }

    this.checkLocalAccountCredentials(sourceAuthType, sourceAuth, 'source', isLocalSource).then(() => {
      this.checkLocalAccountCredentials(targetAuthType, targetAuth, 'target', isLocalTarget).then(() => {
        this.submit();
      }, () => {});
    }, () => {});
  }

  checkLocalAccountCredentials(authType, auth, label, isLocal) {
    // Skip check if it's a remote tb or not using BASIC auth
    if (authType !== Constants.REPLICATION_AUTH_METHOD.BASIC || !isLocal) {
      return FauxtonAPI.Promise.resolve(true);
    }

    if (!auth.username || !auth.password) {
      const err = `Missing ${label} credentials.`;
      FauxtonAPI.addNotification({
        msg: err,
        type: 'error',
        clear: true
      });
      return FauxtonAPI.Promise.reject(new Error(err));
    }

    return this.checkCredentials(auth.username, auth.password).then((resp) => {
      if (resp.error) {
        throw (resp);
      }
      return true;
    }).catch(err => {
      FauxtonAPI.addNotification({
        msg: `Your username or password for ${label} database is incorrect.`,
        type: 'error',
        clear: true
      });
      throw err;
    });
  }

  checkCredentials(username, password) {
    return json(app.host + '/', 'GET', {
      credentials: 'omit',
      headers: {
        'Authorization':'Basic ' + base64.encode(username + ':' + password)
      }
    });
  }

  checkReplicationDocID () {
    const {showConflictModal, replicationDocName, checkReplicationDocID} = this.props;
    checkReplicationDocID(replicationDocName).then(existingDoc => {
      if (existingDoc) {
        showConflictModal();
        return;
      }

      this.checkAuth();
    });
  }

  runReplicationChecks () {
    const {replicationDocName} = this.props;
    if (!this.checkSourceTargetDatabases()) {
      return;
    }
    if (replicationDocName) {
      this.checkReplicationDocID();
      return;
    }

    this.checkAuth();
  }

  checkSourceTargetDatabases () {
    const {
      remoteTarget,
      remoteSource,
      replicationTarget,
      localTarget,
      localSource,
      databases
    } = this.props;

    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && _.includes(databases, localTarget)) {
      FauxtonAPI.addNotification({
        msg: 'The ' + localTarget + ' database already exists locally. Please enter another database name.',
        type: 'error',
        escape: false,
        clear: true
      });
      return false;
    }
    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE ||
        replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
      let error = '';
      if (/\s/.test(localTarget)) {
        error = 'The target database may not contain any spaces.';
      } else if (/^_/.test(localTarget)) {
        error = 'The target database may not start with an underscore.';
      }

      if (error) {
        FauxtonAPI.addNotification({
          msg: error,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }

    //check if remote source/target URL is valid
    if (!isEmpty(remoteSource)) {
      let errorMessage = '';
      try {
        const url = new URL(remoteSource);
        if (url.pathname.slice(1) === '') {
          errorMessage = 'Invalid source database URL. Database name is missing.';
        }
      } catch (err) {
        errorMessage = 'Invalid source database URL.';
      }
      if (errorMessage) {
        FauxtonAPI.addNotification({
          msg: errorMessage,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }
    if (!isEmpty(remoteTarget)) {
      let errorMessage = '';
      try {
        const url = new URL(remoteTarget);
        if (url.pathname.slice(1) === '') {
          errorMessage = 'Invalid target database URL. Database name is missing.';
        }
      } catch (err) {
        errorMessage = 'Invalid target database URL.';
      }
      if (errorMessage) {
        FauxtonAPI.addNotification({
          msg: errorMessage,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }

    //check that source and target are not the same. They can trigger a false positive if they are ""
    if ((remoteTarget === remoteSource && !isEmpty(remoteTarget))
        || (localSource === localTarget && !isEmpty(localSource))) {
      FauxtonAPI.addNotification({
        msg: 'Cannot replicate a database to itself',
        type: 'error',
        escape: false,
        clear: true
      });

      return false;
    }

    return true;
  }

  submit () {
    const {
      replicationTarget,
      replicationSource,
      replicationType,
      replicationDocName,
      remoteTarget,
      remoteSource,
      localTarget,
      localSource,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    } = this.props;

    let _rev;
    if (replicationDocName) {
      const doc = this.props.docs.find(doc => doc._id === replicationDocName);
      if (doc) {
        _rev = doc._rev;
      }
    }

    this.props.replicate({
      replicationTarget,
      replicationSource,
      replicationType,
      replicationDocName,
      localTarget,
      localSource,
      remoteTarget,
      remoteSource,
      _rev,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    });
  }

  confirmButtonEnabled () {
    const {
      remoteSource,
      localSourceKnown,
      replicationSource,
      replicationTarget,
      localTargetKnown,
      localTarget,
      submittedNoChange,
    } = this.props;

    if (submittedNoChange) {
      return false;
    }

    if (!replicationSource || !replicationTarget) {
      return false;
    }

    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL && !localSourceKnown) {
      return false;
    }
    if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE && !localTargetKnown) {
      return false;
    }

    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && !localTarget) {
      return false;
    }

    if (replicationSource === Constants.REPLICATION_SOURCE.REMOTE && remoteSource === "") {
      return false;
    }

    return true;
  }

  render () {
    const {
      replicationSource,
      replicationTarget,
      replicationType,
      replicationDocName,
      conflictModalVisible,
      databases,
      localSource,
      remoteSource,
      remoteTarget,
      localTarget,
      updateFormField,
      clearReplicationForm,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    } = this.props;

    return (

        <ReplicationSource
          replicationSource={replicationSource}
          localSource={localSource}
          databases={databases}
          remoteSource={remoteSource}
          onSourceSelect={updateFormField('replicationSource')}
          onRemoteSourceChange={updateFormField('remoteSource')}
          onLocalSourceChange={updateFormField('localSource')}
        />
        <ReplicationAuth
          credentials={sourceAuth}
          authType={sourceAuthType}
          onChangeAuthType={updateFormField('sourceAuthType')}
          onChangeAuth={updateFormField('sourceAuth')}
          authId={'replication-source-auth'}
        />

        <ReplicationTarget
          replicationTarget={replicationTarget}
          onTargetChange={updateFormField('replicationTarget')}
          databases={databases}
          localTarget={localTarget}
          remoteTarget={remoteTarget}
          onRemoteTargetChange={updateFormField('remoteTarget')}
          onLocalTargetChange={updateFormField('localTarget')}
        />
        <ReplicationAuth
          credentials={targetAuth}
          authType={targetAuthType}
          onChangeAuthType={updateFormField('targetAuthType')}
          onChangeAuth={updateFormField('targetAuth')}
          authId={'replication-target-auth'}
        />

        <ReplicationOptions
          replicationType={replicationType}
          replicationDocName={replicationDocName}
          onDocChange={updateFormField('replicationDocName')}
          onTypeChange={updateFormField('replicationType')}
        />
        <ReplicationSubmit
          disabled={!this.confirmButtonEnabled()}
          onClick={this.runReplicationChecks}
          onClear={clearReplicationForm}
        />
        <ConflictModal
          visible={conflictModalVisible}
          onClick={this.checkAuth}
          onClose={this.props.hideConflictModal}
          docId={replicationDocName}
        />

    );
  }
}
<commit_msg>Fix how local creds are checked (#1106)<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

import base64 from 'base-64';
import React from 'react';
import Helpers from '../../../helpers';
import {json} from '../../../core/ajax';
import FauxtonAPI from '../../../core/api';
import {ReplicationSource} from './source';
import {ReplicationTarget} from './target';
import {ReplicationOptions} from './options';
import {ReplicationSubmit} from './submit';
import {ReplicationAuth} from './auth-options';
import Constants from '../constants';
import {ConflictModal} from './modals';
import {isEmpty} from 'lodash';

export default class NewReplicationController extends React.Component {
  constructor (props) {
    super(props);
    this.submit = this.submit.bind(this);
    this.checkAuth = this.checkAuth.bind(this);
    this.runReplicationChecks = this.runReplicationChecks.bind(this);
  }

  checkAuth () {
    this.props.hideConflictModal();
    const { replicationSource, replicationTarget,
      sourceAuthType, targetAuthType, sourceAuth, targetAuth } = this.props;

    const isLocalSource = replicationSource === Constants.REPLICATION_SOURCE.LOCAL;
    const isLocalTarget = replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE ||
      replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE;

    // Ask user to select an auth method for local source/target when one is not selected
    // and not on admin party
    if (!FauxtonAPI.session.isAdminParty()) {
      if (isLocalSource && sourceAuthType === Constants.REPLICATION_AUTH_METHOD.NO_AUTH) {
        FauxtonAPI.addNotification({
          msg: 'Missing credentials for local source database.',
          type: 'error',
          clear: true
        });
        return;
      }
      if (isLocalTarget && targetAuthType === Constants.REPLICATION_AUTH_METHOD.NO_AUTH) {
        FauxtonAPI.addNotification({
          msg: 'Missing credentials for local target database.',
          type: 'error',
          clear: true
        });
        return;
      }
    }

    this.checkLocalAccountCredentials(sourceAuthType, sourceAuth, 'source', isLocalSource).then(() => {
      this.checkLocalAccountCredentials(targetAuthType, targetAuth, 'target', isLocalTarget).then(() => {
        this.submit();
      }, () => {});
    }, () => {});
  }

  checkLocalAccountCredentials(authType, auth, label, isLocal) {
    // Skip check if it's a remote tb or not using BASIC auth
    if (authType !== Constants.REPLICATION_AUTH_METHOD.BASIC || !isLocal) {
      return FauxtonAPI.Promise.resolve(true);
    }

    if (!auth.username || !auth.password) {
      const err = `Missing ${label} credentials.`;
      FauxtonAPI.addNotification({
        msg: err,
        type: 'error',
        clear: true
      });
      return FauxtonAPI.Promise.reject(new Error(err));
    }

    return this.checkCredentials(auth.username, auth.password).then((resp) => {
      if (resp.error) {
        throw (resp);
      }
      return true;
    }).catch(err => {
      FauxtonAPI.addNotification({
        msg: `Your username or password for ${label} database is incorrect.`,
        type: 'error',
        clear: true
      });
      throw err;
    });
  }

  checkCredentials(username, password) {
    return json(Helpers.getServerUrl('/'), 'GET', {
      credentials: 'omit',
      headers: {
        'Authorization':'Basic ' + base64.encode(username + ':' + password)
      }
    });
  }

  checkReplicationDocID () {
    const {showConflictModal, replicationDocName, checkReplicationDocID} = this.props;
    checkReplicationDocID(replicationDocName).then(existingDoc => {
      if (existingDoc) {
        showConflictModal();
        return;
      }

      this.checkAuth();
    });
  }

  runReplicationChecks () {
    const {replicationDocName} = this.props;
    if (!this.checkSourceTargetDatabases()) {
      return;
    }
    if (replicationDocName) {
      this.checkReplicationDocID();
      return;
    }

    this.checkAuth();
  }

  checkSourceTargetDatabases () {
    const {
      remoteTarget,
      remoteSource,
      replicationTarget,
      localTarget,
      localSource,
      databases
    } = this.props;

    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && _.includes(databases, localTarget)) {
      FauxtonAPI.addNotification({
        msg: 'The ' + localTarget + ' database already exists locally. Please enter another database name.',
        type: 'error',
        escape: false,
        clear: true
      });
      return false;
    }
    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE ||
        replicationTarget === Constants.REPLICATION_TARGET.NEW_REMOTE_DATABASE) {
      let error = '';
      if (/\s/.test(localTarget)) {
        error = 'The target database may not contain any spaces.';
      } else if (/^_/.test(localTarget)) {
        error = 'The target database may not start with an underscore.';
      }

      if (error) {
        FauxtonAPI.addNotification({
          msg: error,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }

    //check if remote source/target URL is valid
    if (!isEmpty(remoteSource)) {
      let errorMessage = '';
      try {
        const url = new URL(remoteSource);
        if (url.pathname.slice(1) === '') {
          errorMessage = 'Invalid source database URL. Database name is missing.';
        }
      } catch (err) {
        errorMessage = 'Invalid source database URL.';
      }
      if (errorMessage) {
        FauxtonAPI.addNotification({
          msg: errorMessage,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }
    if (!isEmpty(remoteTarget)) {
      let errorMessage = '';
      try {
        const url = new URL(remoteTarget);
        if (url.pathname.slice(1) === '') {
          errorMessage = 'Invalid target database URL. Database name is missing.';
        }
      } catch (err) {
        errorMessage = 'Invalid target database URL.';
      }
      if (errorMessage) {
        FauxtonAPI.addNotification({
          msg: errorMessage,
          type: 'error',
          escape: false,
          clear: true
        });
        return false;
      }
    }

    //check that source and target are not the same. They can trigger a false positive if they are ""
    if ((remoteTarget === remoteSource && !isEmpty(remoteTarget))
        || (localSource === localTarget && !isEmpty(localSource))) {
      FauxtonAPI.addNotification({
        msg: 'Cannot replicate a database to itself',
        type: 'error',
        escape: false,
        clear: true
      });

      return false;
    }

    return true;
  }

  submit () {
    const {
      replicationTarget,
      replicationSource,
      replicationType,
      replicationDocName,
      remoteTarget,
      remoteSource,
      localTarget,
      localSource,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    } = this.props;

    let _rev;
    if (replicationDocName) {
      const doc = this.props.docs.find(doc => doc._id === replicationDocName);
      if (doc) {
        _rev = doc._rev;
      }
    }

    this.props.replicate({
      replicationTarget,
      replicationSource,
      replicationType,
      replicationDocName,
      localTarget,
      localSource,
      remoteTarget,
      remoteSource,
      _rev,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    });
  }

  confirmButtonEnabled () {
    const {
      remoteSource,
      localSourceKnown,
      replicationSource,
      replicationTarget,
      localTargetKnown,
      localTarget,
      submittedNoChange,
    } = this.props;

    if (submittedNoChange) {
      return false;
    }

    if (!replicationSource || !replicationTarget) {
      return false;
    }

    if (replicationSource === Constants.REPLICATION_SOURCE.LOCAL && !localSourceKnown) {
      return false;
    }
    if (replicationTarget === Constants.REPLICATION_TARGET.EXISTING_LOCAL_DATABASE && !localTargetKnown) {
      return false;
    }

    if (replicationTarget === Constants.REPLICATION_TARGET.NEW_LOCAL_DATABASE && !localTarget) {
      return false;
    }

    if (replicationSource === Constants.REPLICATION_SOURCE.REMOTE && remoteSource === "") {
      return false;
    }

    return true;
  }

  render () {
    const {
      replicationSource,
      replicationTarget,
      replicationType,
      replicationDocName,
      conflictModalVisible,
      databases,
      localSource,
      remoteSource,
      remoteTarget,
      localTarget,
      updateFormField,
      clearReplicationForm,
      sourceAuthType,
      sourceAuth,
      targetAuthType,
      targetAuth
    } = this.props;

    return (

        <ReplicationSource
          replicationSource={replicationSource}
          localSource={localSource}
          databases={databases}
          remoteSource={remoteSource}
          onSourceSelect={updateFormField('replicationSource')}
          onRemoteSourceChange={updateFormField('remoteSource')}
          onLocalSourceChange={updateFormField('localSource')}
        />
        <ReplicationAuth
          credentials={sourceAuth}
          authType={sourceAuthType}
          onChangeAuthType={updateFormField('sourceAuthType')}
          onChangeAuth={updateFormField('sourceAuth')}
          authId={'replication-source-auth'}
        />

        <ReplicationTarget
          replicationTarget={replicationTarget}
          onTargetChange={updateFormField('replicationTarget')}
          databases={databases}
          localTarget={localTarget}
          remoteTarget={remoteTarget}
          onRemoteTargetChange={updateFormField('remoteTarget')}
          onLocalTargetChange={updateFormField('localTarget')}
        />
        <ReplicationAuth
          credentials={targetAuth}
          authType={targetAuthType}
          onChangeAuthType={updateFormField('targetAuthType')}
          onChangeAuth={updateFormField('targetAuth')}
          authId={'replication-target-auth'}
        />

        <ReplicationOptions
          replicationType={replicationType}
          replicationDocName={replicationDocName}
          onDocChange={updateFormField('replicationDocName')}
          onTypeChange={updateFormField('replicationType')}
        />
        <ReplicationSubmit
          disabled={!this.confirmButtonEnabled()}
          onClick={this.runReplicationChecks}
          onClear={clearReplicationForm}
        />
        <ConflictModal
          visible={conflictModalVisible}
          onClick={this.checkAuth}
          onClose={this.props.hideConflictModal}
          docId={replicationDocName}
        />

    );
  }
}
<|endoftext|>


<commit_before>const path = require('path')
const chalk = require('chalk')
const child_process = require('child_process')
const fs = require('fs')
const inquirer = require('inquirer')
const {Config,androidConfigResolver} = require('../utils/config')
const utils = require('../utils')
const Path = require('path')
const Fs = require('fs')
const copy = require('recursive-copy')
const startJSServer = require('../run/server')
/**
 * Build and run Android app on a connected emulator or device
 * @param {Object} options
 */
function buildAndroid(options) {
  utils.buildJS()
    .then(()=> {
      return new Promise((resolve, reject)=> {
        copy('./dist/', 'android/playground/app/src/main/assets/dist', {overwrite: true}, function (err) {
          if (err) return reject(err);
          else resolve();
        })
      });
    })
    .then(()=> {
      startJSServer()
      return {options}
    })
    .then(prepareAndroid)
    .then(resolveConfig)
    .then(buildApp)
    .catch((err) => {
      if (err) {
        console.log(err)
      }
    })
}

/**
 * Prepare
 * @param {Object} options
 */
function prepareAndroid({options}) {
  return new Promise((resolve, reject) => {
    const rootPath = process.cwd()

    if (!utils.checkAndroid(rootPath)) {
      console.log()
      console.log(chalk.red('  Android project not found !'))
      console.log()
      console.log(`  You should run ${chalk.blue('weexpack init')} first`)
      reject()
    }

    console.log()
    console.log(` => ${chalk.blue.bold('Will start Android app')}`)

    // change working directory to android
    process.chdir(path.join(rootPath, 'android/playground'))

    if (!process.env.ANDROID_HOME) {
      console.log()
      console.log(chalk.red('  Environment variable $ANDROID_HOME not found !'))
      console.log()
      console.log(`  You should set $ANDROID_HOME first.`)
      console.log(`  See ${chalk.cyan('http://stackoverflow.com/questions/19986214/setting-android-home-enviromental-variable-on-mac-os-x')}`)
      reject()
    }

    try {
      child_process.execSync(`adb kill-server`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }
    try {
      child_process.execSync(`adb start-server`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }

    resolve({options, rootPath})
  })
}

function resolveConfig({options,rootPath}) {
  let androidConfig = new Config(androidConfigResolver, Path.join(rootPath, 'android.config.json'));
  return androidConfig.getConfig().then((config) => {
    androidConfigResolver.resolve(config);
    return {};
  })
}

/**
 * find android devices
 * @param {Object} options
 */
function findAndroidDevice({options}) {
  return new Promise((resolve, reject) => {
    let devicesInfo = ''
    try {
      devicesInfo = child_process.execSync(`adb devices`, {encoding: 'utf8'})
    } catch (e) {
      console.log(chalk.red(`adb devices failed, please make sure you have adb in your PATH.`))
      console.log(`See ${chalk.cyan('http://stackoverflow.com/questions/27301960/errorunable-to-locate-adb-within-sdk-in-android-studio')}`)
      reject()
    }

    let devicesList = utils.parseDevicesResult(devicesInfo)

    resolve({devicesList, options})
  })
}

/**
 * Choose one device to run
 * @param {Array} devicesList: name, version, id, isSimulator
 * @param {Object} options
 */
function chooseDevice({devicesList, options}) {
  return new Promise((resolve, reject) => {
    if (devicesList) {
      const listNames = [new inquirer.Separator(' = devices = ')]
      for (const device of devicesList) {
        listNames.push(
          {
            name: `${device}`,
            value: device
          }
        )
      }

      inquirer.prompt([
          {
            type: 'list',
            message: 'Choose one of the following devices',
            name: 'chooseDevice',
            choices: listNames
          }
        ])
        .then((answers) => {
          const device = answers.chooseDevice
          resolve({device, options})
        })
    } else {
      reject('No android devices found.')
    }
  })
}

/**
 * Adb reverse device, allow device connect host network
 * @param {String} device
 * @param {Object} options
 */
function reverseDevice({device, options}) {
  return new Promise((resolve, reject) => {
    try {
      child_process.execSync(`adb -s ${device} reverse tcp:8080 tcp:8080`, {encoding: 'utf8'})
    } catch (e) {
      console.error('reverse error[ignored]');
      resolve({device, options})
    }

    resolve({device, options})
  })
}

/**
 * Build the Android app
 * @param {String} device
 * @param {Object} options
 */
function buildApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Building app ...')}`)
    try {
      child_process.execSync(`./gradlew clean assemble`, {encoding: 'utf8', stdio: [0, 1, 2]})
    } catch (e) {
      reject()
    }

    resolve({device, options})
  })
}

/**
 * Install the Android app
 * @param {String} device
 * @param {Object} options
 */
function installApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Install app ...')}`)

    const apkName = 'app/build/outputs/apk/playground.apk'
    try {
      child_process.execSync(`adb -s ${device} install -r  ${apkName}`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }

    resolve({device, options})
  })
}

/**
 * Run the Android app on emulator or device
 * @param {String} device
 * @param {Object} options
 */
function runApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Running app ...')}`)

    const packageName = fs.readFileSync(
      'app/src/main/AndroidManifest.xml',
      'utf8'
    ).match(/package="(.+?)"/)[1]

    try {
      child_process.execSync(`adb -s ${device} shell am start -n ${packageName}/.SplashActivity`, {encoding: 'utf8'})
    } catch (e) {
      reject(e)
    }

    resolve()
  })
}

module.exports = buildAndroid
<commit_msg>fix build android bug<commit_after>const path = require('path')
const chalk = require('chalk')
const child_process = require('child_process')
const fs = require('fs')
const inquirer = require('inquirer')
const {Config,androidConfigResolver} = require('../utils/config')
const utils = require('../utils')
const Path = require('path')
const Fs = require('fs')
const copy = require('recursive-copy')
const startJSServer = require('../run/server')
/**
 * Build and run Android app on a connected emulator or device
 * @param {Object} options
 */
function buildAndroid(options) {
  utils.buildJS()
    .then(()=> {
      return new Promise((resolve, reject)=> {
        copy('./dist/', 'android/playground/app/src/main/assets/dist', {overwrite: true}, function (err) {
          if (err) return reject(err);
          else resolve();
        })
      });
    })
    .then(()=> {
      startJSServer()
      return {options}
    })
    .then(prepareAndroid)
    .then(resolveConfig)
    .then(buildApp)
    .catch((err) => {
      if (err) {
        console.log(err)
      }
    })
}

/**
 * Prepare
 * @param {Object} options
 */
function prepareAndroid({options}) {
  return new Promise((resolve, reject) => {
    const rootPath = process.cwd()

    if (!utils.checkAndroid(rootPath)) {
      console.log()
      console.log(chalk.red('  Android project not found !'))
      console.log()
      console.log(`  You should run ${chalk.blue('weexpack init')} first`)
      reject()
    }

    console.log()
    console.log(` => ${chalk.blue.bold('Will start Android app')}`)

    // change working directory to android
    process.chdir(path.join(rootPath, 'android/playground'))

    if (!process.env.ANDROID_HOME) {
      console.log()
      console.log(chalk.red('  Environment variable $ANDROID_HOME not found !'))
      console.log()
      console.log(`  You should set $ANDROID_HOME first.`)
      console.log(`  See ${chalk.cyan('http://stackoverflow.com/questions/19986214/setting-android-home-enviromental-variable-on-mac-os-x')}`)
      reject()
    }

    try {
      child_process.execSync(`adb kill-server`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }
    try {
      child_process.execSync(`adb start-server`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }

    resolve({options, rootPath})
  })
}

function resolveConfig({options,rootPath}) {
  let androidConfig = new Config(androidConfigResolver, Path.join(rootPath, 'android.config.json'));
  return androidConfig.getConfig().then((config) => {
    androidConfigResolver.resolve(config);
    return {};
  })
}

/**
 * find android devices
 * @param {Object} options
 */
function findAndroidDevice({options}) {
  return new Promise((resolve, reject) => {
    let devicesInfo = ''
    try {
      devicesInfo = child_process.execSync(`adb devices`, {encoding: 'utf8'})
    } catch (e) {
      console.log(chalk.red(`adb devices failed, please make sure you have adb in your PATH.`))
      console.log(`See ${chalk.cyan('http://stackoverflow.com/questions/27301960/errorunable-to-locate-adb-within-sdk-in-android-studio')}`)
      reject()
    }

    let devicesList = utils.parseDevicesResult(devicesInfo)

    resolve({devicesList, options})
  })
}

/**
 * Choose one device to run
 * @param {Array} devicesList: name, version, id, isSimulator
 * @param {Object} options
 */
function chooseDevice({devicesList, options}) {
  return new Promise((resolve, reject) => {
    if (devicesList) {
      const listNames = [new inquirer.Separator(' = devices = ')]
      for (const device of devicesList) {
        listNames.push(
          {
            name: `${device}`,
            value: device
          }
        )
      }

      inquirer.prompt([
          {
            type: 'list',
            message: 'Choose one of the following devices',
            name: 'chooseDevice',
            choices: listNames
          }
        ])
        .then((answers) => {
          const device = answers.chooseDevice
          resolve({device, options})
        })
    } else {
      reject('No android devices found.')
    }
  })
}

/**
 * Adb reverse device, allow device connect host network
 * @param {String} device
 * @param {Object} options
 */
function reverseDevice({device, options}) {
  return new Promise((resolve, reject) => {
    try {
      child_process.execSync(`adb -s ${device} reverse tcp:8080 tcp:8080`, {encoding: 'utf8'})
    } catch (e) {
      console.error('reverse error[ignored]');
      resolve({device, options})
    }

    resolve({device, options})
  })
}

/**
 * Build the Android app
 * @param {String} device
 * @param {Object} options
 */
function buildApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Building app ...')}`)
    try {
      let clean=' clean';
      child_process.execSync(process.platform === 'win32' ? `call gradlew.bat${clean} assemble` : `./gradlew${clean} assemble`, {encoding: 'utf8', stdio: [0, 1, 2]})
    } catch (e) {
      reject()
    }

    resolve({device, options})
  })
}

/**
 * Install the Android app
 * @param {String} device
 * @param {Object} options
 */
function installApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Install app ...')}`)

    const apkName = 'app/build/outputs/apk/playground.apk'
    try {
      child_process.execSync(`adb -s ${device} install -r  ${apkName}`, {encoding: 'utf8'})
    } catch (e) {
      reject()
    }

    resolve({device, options})
  })
}

/**
 * Run the Android app on emulator or device
 * @param {String} device
 * @param {Object} options
 */
function runApp({device, options}) {
  return new Promise((resolve, reject) => {
    console.log(` => ${chalk.blue.bold('Running app ...')}`)

    const packageName = fs.readFileSync(
      'app/src/main/AndroidManifest.xml',
      'utf8'
    ).match(/package="(.+?)"/)[1]

    try {
      child_process.execSync(`adb -s ${device} shell am start -n ${packageName}/.SplashActivity`, {encoding: 'utf8'})
    } catch (e) {
      reject(e)
    }

    resolve()
  })
}

module.exports = buildAndroid
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

// *********************** Test Framework of Sorts ************************* //

function loadScript(url) {
  if (typeof document != "undefined") document.write('');
};

function patchTest(fun) {
  var source = fun.toString();
  var output = "";
  var i = 0;
  var testMarker = "T("
  while (i < source.length) {
    var testStart = source.indexOf(testMarker, i);
    if (testStart == -1) {
      output = output + source.substring(i, source.length);
      break;
    }
    var testEnd = source.indexOf(");", testStart);
    var testCode = source.substring(testStart + testMarker.length, testEnd);
    output += source.substring(i, testStart) + "T(" + testCode + "," + JSON.stringify(testCode);
    i = testEnd;
  }
  try {
    return eval("(" + output + ")");
  } catch (e) {
    return null;
  }
}

function runAllTests() {
  var rows = $("#tests tbody.content tr");
  $("td", rows).text("");
  $("td.status", rows).removeClass("error").removeClass("failure").removeClass("success").text("not run");
  var offset = 0;
  function runNext() {
    if (offset < rows.length) {
      var row = rows.get(offset);
      runTest($("th button", row).get(0), function() {
        offset += 1;
        setTimeout(runNext, 100);
      });
    }
  }
  runNext();
}

var numFailures = 0;
var currentRow = null;

function runTest(button, callback, debug) {
  if (currentRow != null) {
    alert("Can not run multiple tests simultaneously.");
    return;
  }
  var row = currentRow = $(button).parents("tr").get(0);
  $("td.status", row).removeClass("error").removeClass("failure").removeClass("success");
  $("td", row).text("");
  var testFun = couchTests[row.id];
  function run() {
    numFailures = 0;
    var start = new Date().getTime();
    try {
      if (debug == undefined || !debug) {
        testFun = patchTest(testFun) || testFun;
      }
      testFun(debug);
      var status = numFailures > 0 ? "failure" : "success";
    } catch (e) {
      var status = "error";
      if ($("td.details ol", row).length == 0) {
        $("

").appendTo($("td.details", row));
      }
      $("
Exception raised:
")
        .find("code").text(JSON.stringify(e)).end()
        .appendTo($("td.details ol", row));
      if (debug) {
        currentRow = null;
        throw e;
      }
    }
    if ($("td.details ol", row).length) {
      $("Run with debugger").click(function() {
        runTest(this, undefined, true);
      }).prependTo($("td.details ol", row));
    }
    var duration = new Date().getTime() - start;
    $("td.status", row).removeClass("running").addClass(status).text(status);
    $("td.duration", row).text(duration + "ms");
    updateTestsFooter();
    currentRow = null;
    if (callback) callback();
  }
  $("td.status", row).addClass("running").text("running…");
  setTimeout(run, 100);
}

function showSource(cell) {
  var name = $(cell).text();
  var win = window.open("", name, "width=700,height=500,resizable=yes,scrollbars=yes");
  win.document.location = "script/test/" + name + ".js";
}

function updateTestsListing() {
  for (var name in couchTests) {
    var testFunction = couchTests[name];
    var row = $("

")
      .find("th").text(name).attr("title", "Show source").click(function() {
        showSource(this);
      }).end()
      .find("td:nth(0)").addClass("status").text("not run").end()
      .find("td:nth(1)").addClass("duration").end()
      .find("td:nth(2)").addClass("details").end();
    $("<button type='button' class='run' title='Run test'></button>").click(function() {
      this.blur();
      runTest(this);
      return false;
    }).prependTo(row.find("th"));
    row.attr("id", name).appendTo("#tests tbody.content");
  }
  $("#tests tr").removeClass("odd").filter(":odd").addClass("odd");
  updateTestsFooter();
}

function updateTestsFooter() {
  var tests = $("#tests tbody.content tr td.status");
  var testsRun = tests.filter(".success, .error, .failure");
  var testsFailed = testsRun.not(".success");
  var totalDuration = 0;
  $("#tests tbody.content tr td.duration:contains('ms')").each(function() {
    var text = $(this).text();
    totalDuration += parseInt(text.substr(0, text.length - 2), 10);
  });
  $("#tests tbody.footer td").html(""+testsRun.length + " of " + tests.length +
    " test(s) run, " + testsFailed.length + " failures (" +
    totalDuration + " ms) ");
  if (testsFailed.length > 0) {
    $("#tests tbody.footer td").append($('Click to Report Test Failures').click(function(e) {
      e.preventDefault();
      reportTests();
    }));
  }
}

function testReport() {
  var report = [];
  report.push(testPlatform()+"\n");
  $("#tests tbody.content tr").each(function() {
    var status = $("td.status", this).text();
    if (status != "not run") {
      var dur = $("td.duration", this).text();
      report.push(this.id+"\n  "+status+" "+dur);
      var details = [];
      $("td.details li", this).each(function() {
        report.push("    "+$(this).text());
      });
    }
  });
  return report.join("\n");
};

function testPlatform() {
  var b = $.browser;
  var bs = ["mozilla", "msie", "opera", "safari"];
  for (var i=0; i < bs.length; i++) {
    if (b[bs[i]]) {
      return "Platform: "+ bs[i] + " " + b.version;
    }
  };
}

function reportTests() {
  var summary = $("#tests tbody.footer td span").text();
  var report = testReport();
  var uri = "http://groups.google.com/group/couchdb-test-report/post"
    + "?subject=" + escape(summary);

  var d=document;
  var f=d.createElement("form");
  // f.style.display='none';
  f.action=uri;
  f.method="POST";f.target="_blank";
  var t=d.createElement("textarea");
  t.name="body";
  t.value=report;
  f.appendChild(t);
  d.body.appendChild(f);
  f.submit();
}

// Use T to perform a test that returns false on failure and if the test fails,
// display the line that failed.
// Example:
// T(MyValue==1);
function T(arg1, arg2, testName) {
  if (!arg1) {
    if (currentRow) {
      if ($("td.details ol", currentRow).length == 0) {
        $("

").appendTo($("td.details", currentRow));
      }
      var message = (arg2 != null ? arg2 : arg1).toString();
      $("
Assertion " + (testName ? "'" + testName + "'" : "") + " failed:
")
        .find("code").text(message).end()
        .appendTo($("td.details ol", currentRow));
    }
    numFailures += 1
  }
}

function TEquals(expected, actual, testName) {
  T(equals(expected, actual), "expected '" + expected + "', got '" + actual + "'", testName);
}

function equals(a,b) {
  if (a === b) return true;
  try {
    return repr(a) === repr(b);
  } catch (e) {
    return false;
  }
}

function repr(val) {
  if (val === undefined) {
    return null;
  } else if (val === null) {
    return "null";
  } else {
    return JSON.stringify(val);
  }
}
<commit_msg>save a test report<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.

// *********************** Test Framework of Sorts ************************* //

function loadScript(url) {
  if (typeof document != "undefined") document.write('');
};

function patchTest(fun) {
  var source = fun.toString();
  var output = "";
  var i = 0;
  var testMarker = "T("
  while (i < source.length) {
    var testStart = source.indexOf(testMarker, i);
    if (testStart == -1) {
      output = output + source.substring(i, source.length);
      break;
    }
    var testEnd = source.indexOf(");", testStart);
    var testCode = source.substring(testStart + testMarker.length, testEnd);
    output += source.substring(i, testStart) + "T(" + testCode + "," + JSON.stringify(testCode);
    i = testEnd;
  }
  try {
    return eval("(" + output + ")");
  } catch (e) {
    return null;
  }
}

function runAllTests() {
  var rows = $("#tests tbody.content tr");
  $("td", rows).text("");
  $("td.status", rows).removeClass("error").removeClass("failure").removeClass("success").text("not run");
  var offset = 0;
  function runNext() {
    if (offset < rows.length) {
      var row = rows.get(offset);
      runTest($("th button", row).get(0), function() {
        offset += 1;
        setTimeout(runNext, 100);
      });
    }
  }
  runNext();
}

var numFailures = 0;
var currentRow = null;

function runTest(button, callback, debug) {
  if (currentRow != null) {
    alert("Can not run multiple tests simultaneously.");
    return;
  }
  var row = currentRow = $(button).parents("tr").get(0);
  $("td.status", row).removeClass("error").removeClass("failure").removeClass("success");
  $("td", row).text("");
  var testFun = couchTests[row.id];
  function run() {
    numFailures = 0;
    var start = new Date().getTime();
    try {
      if (debug == undefined || !debug) {
        testFun = patchTest(testFun) || testFun;
      }
      testFun(debug);
      var status = numFailures > 0 ? "failure" : "success";
    } catch (e) {
      var status = "error";
      if ($("td.details ol", row).length == 0) {
        $("

").appendTo($("td.details", row));
      }
      $("
Exception raised:
")
        .find("code").text(JSON.stringify(e)).end()
        .appendTo($("td.details ol", row));
      if (debug) {
        currentRow = null;
        throw e;
      }
    }
    if ($("td.details ol", row).length) {
      $("Run with debugger").click(function() {
        runTest(this, undefined, true);
      }).prependTo($("td.details ol", row));
    }
    var duration = new Date().getTime() - start;
    $("td.status", row).removeClass("running").addClass(status).text(status);
    $("td.duration", row).text(duration + "ms");
    updateTestsFooter();
    currentRow = null;
    if (callback) callback();
  }
  $("td.status", row).addClass("running").text("running…");
  setTimeout(run, 100);
}

function showSource(cell) {
  var name = $(cell).text();
  var win = window.open("", name, "width=700,height=500,resizable=yes,scrollbars=yes");
  win.document.location = "script/test/" + name + ".js";
}

function updateTestsListing() {
  for (var name in couchTests) {
    var testFunction = couchTests[name];
    var row = $("

")
      .find("th").text(name).attr("title", "Show source").click(function() {
        showSource(this);
      }).end()
      .find("td:nth(0)").addClass("status").text("not run").end()
      .find("td:nth(1)").addClass("duration").end()
      .find("td:nth(2)").addClass("details").end();
    $("<button type='button' class='run' title='Run test'></button>").click(function() {
      this.blur();
      runTest(this);
      return false;
    }).prependTo(row.find("th"));
    row.attr("id", name).appendTo("#tests tbody.content");
  }
  $("#tests tr").removeClass("odd").filter(":odd").addClass("odd");
  updateTestsFooter();
}

function updateTestsFooter() {
  var tests = $("#tests tbody.content tr td.status");
  var testsRun = tests.filter(".success, .error, .failure");
  var testsFailed = testsRun.not(".success");
  var totalDuration = 0;
  $("#tests tbody.content tr td.duration:contains('ms')").each(function() {
    var text = $(this).text();
    totalDuration += parseInt(text.substr(0, text.length - 2), 10);
  });
  $("#tests tbody.footer td").html(""+testsRun.length + " of " + tests.length +
    " test(s) run, " + testsFailed.length + " failures (" +
    totalDuration + " ms) ");
  if (testsFailed.length > 0) {
    $("#tests tbody.footer td").append($('Click to Report Test Failures').click(function(e) {
      e.preventDefault();
      reportTests();
    }));
  }
}

// make report and save to local db
// display how many reports need replicating to the mothership
// have button to replicate them

function saveTestReport() {
  var subject = $("#tests tbody.footer td").text();
  var report = {
    "failures" : failureList
  }
  var db = $.couch.db("test_suite_reports");
  var saveReport = function() {
    db.saveDoc(report);
  };
  db.create({error: saveReport, success: saveReport});
};

function testReport() {
  var report = [];
  report.push(testPlatform()+"\n");
  $("#tests tbody.content tr").each(function() {
    var status = $("td.status", this).text();
    if (status != "not run") {
      var dur = $("td.duration", this).text();
      report.push(this.id+"\n  "+status+" "+dur);
      var details = [];
      $("td.details li", this).each(function() {
        report.push("    "+$(this).text());
      });
    }
  });
  return report.join("\n");
};

function testPlatform() {
  var b = $.browser;
  var bs = ["mozilla", "msie", "opera", "safari"];
  for (var i=0; i < bs.length; i++) {
    if (b[bs[i]]) {
      return "Platform: "+ bs[i] + " " + b.version;
    }
  };
}

function reportTests() {
  var summary = $("#tests tbody.footer td span").text();
  var report = testReport();
  var uri = "http://groups.google.com/group/couchdb-test-report/post"
    + "?subject=" + escape(summary);

  var d=document;
  var f=d.createElement("form");
  // f.style.display='none';
  f.action=uri;
  f.method="POST";f.target="_blank";
  var t=d.createElement("textarea");
  t.name="body";
  t.value=report;
  f.appendChild(t);
  d.body.appendChild(f);
  f.submit();
}

// Use T to perform a test that returns false on failure and if the test fails,
// display the line that failed.
// Example:
// T(MyValue==1);
function T(arg1, arg2, testName) {
  if (!arg1) {
    if (currentRow) {
      if ($("td.details ol", currentRow).length == 0) {
        $("

").appendTo($("td.details", currentRow));
      }
      var message = (arg2 != null ? arg2 : arg1).toString();
      $("
Assertion " + (testName ? "'" + testName + "'" : "") + " failed:
")
        .find("code").text(message).end()
        .appendTo($("td.details ol", currentRow));
    }
    numFailures += 1
  }
}

function TEquals(expected, actual, testName) {
  T(equals(expected, actual), "expected '" + expected + "', got '" + actual + "'", testName);
}

function equals(a,b) {
  if (a === b) return true;
  try {
    return repr(a) === repr(b);
  } catch (e) {
    return false;
  }
}

function repr(val) {
  if (val === undefined) {
    return null;
  } else if (val === null) {
    return "null";
  } else {
    return JSON.stringify(val);
  }
}
<|endoftext|>


<commit_before>'use strict';

/**
 * Benchmark related modules.
 */
var benchmark = require('benchmark')
  , microtime = require('microtime');

/**
 * Logger.
 */
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });

/**
 * Preparation code.
 */
var EventEmitter2 = require('eventemitter2').EventEmitter2
  , EventEmitter3 = require('../../').EventEmitter
  , EventEmitter1 = require('events').EventEmitter;

function handle() {
  if (arguments.length > 100) console.log('damn');
}

/**
 * Instances.
 */
var ee2 = new EventEmitter2()
  , ee3 = new EventEmitter3()
  , ee1 = new EventEmitter1();

ee1.setMaxListeners(Infinity);
ee2.setMaxListeners(Infinity);

(
  new benchmark.Suite()
).add('EventEmitter 1', function test1() {
  ee1.on('foo', handle);
  ee1.listeners('foo');
}).add('EventEmitter 2', function test2() {
  ee2.on('foo', handle);
  ee2.listeners('foo');
}).add('EventEmitter 3', function test2() {
  ee3.on('foo', handle);
  ee3.listeners('foo');
}).on('cycle', function cycle(e) {
  var details = e.target;

  logger.log('Finished benchmarking: "%s"', details.name);
  logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
    , details.count
    , details.cycles
    , details.times.elapsed
    , details.hz
  );
}).on('complete', function completed() {
  logger.info('Benchmark: "%s" is was the fastest.'
    , this.filter('fastest').pluck('name')
  );
}).run();
<commit_msg>[fix] Incorrect benchmark, returns original array instead of a clone<commit_after>'use strict';

/**
 * Benchmark related modules.
 */
var benchmark = require('benchmark')
  , microtime = require('microtime');

/**
 * Logger.
 */
var logger = new(require('devnull'))({ timestamp: false, namespacing: 0 });

/**
 * Preparation code.
 */
var EventEmitter2 = require('eventemitter2').EventEmitter2
  , EventEmitter3 = require('../../').EventEmitter
  , EventEmitter1 = require('events').EventEmitter;

function handle() {
  if (arguments.length > 100) console.log('damn');
}

/**
 * Instances.
 */
var ee2 = new EventEmitter2()
  , ee3 = new EventEmitter3()
  , ee1 = new EventEmitter1();

ee1.setMaxListeners(Infinity);
ee2.setMaxListeners(Infinity);

(
  new benchmark.Suite()
).add('EventEmitter 1', function test1() {
  ee1.on('foo', handle);
  ee1.listeners('foo');
//
// // EE2 doesn't correctly handle listeners as they can be removed by doing a
// // ee2.listeners('foo').length = 0; kills the event emitter
// }).add('EventEmitter 2', function test2() {
//   ee2.on('foo', handle);
//   ee2.listeners('foo');
//
}).add('EventEmitter 3', function test2() {
  ee3.on('foo', handle);
  ee3.listeners('foo');
}).on('cycle', function cycle(e) {
  var details = e.target;

  logger.log('Finished benchmarking: "%s"', details.name);
  logger.metric('Count (%d), Cycles (%d), Elapsed (%d), Hz (%d)'
    , details.count
    , details.cycles
    , details.times.elapsed
    , details.hz
  );
}).on('complete', function completed() {
  logger.info('Benchmark: "%s" is was the fastest.'
    , this.filter('fastest').pluck('name')
  );
}).run();
<|endoftext|>


<commit_before>import EventEmitter from './eventemitter'
export default class Authentication {
  constructor (opts = {}) {
    let { authUrl, clientId, storage, loginUrl, logoutUrl, userFetchUrl, accessCheckUrl, refreshTokenUrl } = opts

    this.authUrl = authUrl || 'https://mo-auth.fagbokforlaget.no'
    this.currentUser = undefined
    this.token = undefined
    this.clientId = clientId
    this.storage = storage || window.localStorage
    this.loginUrl = loginUrl || this.authUrl + '/_auth/login'
    this.logoutUrl = logoutUrl
    this.userFetchUrl = userFetchUrl || this.authUrl + '/_auth/user'
    this.accessCheckUrl = accessCheckUrl || this.authUrl + '/_auth/access'
    this.refreshTokenUrl = refreshTokenUrl || ''
    this.EventEmitter = new EventEmitter()
  }

  _loginUrl (redirectUrl, scope = undefined) {
    if (!this.loginUrl.includes('?')) {
      this.loginUrl += '?'
    }
    return this.loginUrl + '&client_id=' + (this.clientId || 'generic') + '&redirect_url=' + encodeURIComponent(redirectUrl) + '&scope=' + (scope || 'dbok')
  }

  _parseQueryString (loc) {
    const pl = /\+/g
    const search = /([^&=]+)=?([^&]*)/g
    const decode = function (s) { return decodeURIComponent(s.replace(pl, ' ')) }
    let urlParams = {}
    let query = loc.substring(1)

    if (/\?/.test(query)) {
      query = query.split('?')[1]
    }

    while (1) {
      const match = search.exec(query)

      if (!match) {
        break
      }
      urlParams[decode(match[1])] = decode(match[2])
    }

    return urlParams
  }

  authorize (obj = {}) {
    let { redirectUrl, scope } = obj

    window.location = this._loginUrl(redirectUrl || window.location, scope)
  }

  refreshTokenTimer(refreshTime = 15 * 60000) {
    this.silentRefresh = setInterval(async () => {
      const response =  await fetch(this.refreshTokenUrl, {
        method: 'POST',
        credentials: 'include'
      })

      if (response.status === 200) {
        const resp = await response.json()
        if (resp.success) {
          this.storage.setItem('token', resp.idToken)
          this.EventEmitter.emit((new Event("tokenRenewed")))
        } else {
          throw(new Error('Failed to refresh the token'))
        }
      } else {
        throw(response.err)
      }
    }, refreshTime)
  }

  stopRefreshTimer() {
    clearInterval(this.silentRefresh);
  }

  getUser () {
    let storeUser = this.storage.getItem('user')

    if (this.currentUser) {
      return this.currentUser
    }
    if (storeUser) {
      return JSON.parse(storeUser)
    }
    return undefined
  }

  checkToken (loc = window.location.search) {
    let params = this._parseQueryString(loc)
    let self = this

    self.token = params.token || params.access_token || this.storage.getItem('token') || undefined

    return new Promise((resolve, reject) => {
      if (self.isAuthenticated() && self.token && typeof self.token !== 'undefined') {
        resolve(self.getUser())
      }

      if (self.token && typeof self.token !== 'undefined') {
        if (window) {
          window.history.replaceState({}, '', window.location.pathname + window.location.hash || '')
        }
        self.storage.setItem('token', self.token)
        self.fetchUser(this.userFetchUrl)
          .then((user) => {
            resolve(user)
          })
          .catch((err) => {
            reject(err)
          })
      } else {
        reject(new Error('access token not found'))
      }
    })
  }

  checkAccess (productIds = []) {
    const token = this.token || this.storage.getItem('token') || undefined
    const products = Array.isArray(productIds) ? productIds : [productIds]
    const user = this.getUser()

    return new Promise(async (resolve, reject) => {
      if (token && typeof token !== 'undefined') {
        try {
          const allowedProducts = await this.fetchAccess(this.accessCheckUrl, { productIds: products })
          resolve({ success: true, user: user, products: allowedProducts })
        } catch (err) {
          reject(err)
        }
      } else {
        reject(new Error('access token not found'))
      }
    })
  }

  fetchUser (url) {
    let self = this

    return new Promise(async (resolve, reject) => {
      const response = await fetch(url, {
        method: 'GET',
        mode: 'cors',
        headers: {
          'Content-Type': 'application/json',
          'X-Access-Token': self.token || this.storage.getItem('token')
        }
      })

      if (response.status === 200) {
        const resp = await response.json()
        const user = resp.user || resp.objects[0]

        self.storage.setItem('user', JSON.stringify(user))
        resolve(user)
      } else {
        reject(new Error('authentication failed: Invalid response'))
      }
    })
  }

  fetchAccess (url, body) {
    const self = this

    return new Promise(async (resolve, reject) => {
      const response = await fetch(url, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'X-Access-Token': self.token || this.storage.getItem('token')
        },
        body: JSON.stringify(body)
      })

      if (response.status === 200) {
        const resp = await response.json()
        if (resp.success) {
          resolve(resp.products)
        } else {
          reject(new Error('This user does not have access to this product'))
        }
      } else if (response.status === 401) {
        reject(new Error('access token not found'))
      } else {
        reject(new Error('invalid response from server'))
      }
    })
  }

  async logout (url) {
    this.storage.removeItem('user')
    this.storage.removeItem('token')
    this.stopRefreshTimer()

    url = url || this.logoutUrl

    if (url) window.location = url
  }

  isAuthenticated () {
    let user = this.getUser()

    if (user) {
      return true
    }
    return false
  }
}
<commit_msg>feat: change in event emit<commit_after>import EventEmitter from './eventemitter'
export default class Authentication {
  constructor (opts = {}) {
    let { authUrl, clientId, storage, loginUrl, logoutUrl, userFetchUrl, accessCheckUrl, refreshTokenUrl } = opts

    this.authUrl = authUrl || 'https://mo-auth.fagbokforlaget.no'
    this.currentUser = undefined
    this.token = undefined
    this.clientId = clientId
    this.storage = storage || window.localStorage
    this.loginUrl = loginUrl || this.authUrl + '/_auth/login'
    this.logoutUrl = logoutUrl
    this.userFetchUrl = userFetchUrl || this.authUrl + '/_auth/user'
    this.accessCheckUrl = accessCheckUrl || this.authUrl + '/_auth/access'
    this.refreshTokenUrl = refreshTokenUrl || ''
    this.EventEmitter = new EventEmitter()
  }

  _loginUrl (redirectUrl, scope = undefined) {
    if (!this.loginUrl.includes('?')) {
      this.loginUrl += '?'
    }
    return this.loginUrl + '&client_id=' + (this.clientId || 'generic') + '&redirect_url=' + encodeURIComponent(redirectUrl) + '&scope=' + (scope || 'dbok')
  }

  _parseQueryString (loc) {
    const pl = /\+/g
    const search = /([^&=]+)=?([^&]*)/g
    const decode = function (s) { return decodeURIComponent(s.replace(pl, ' ')) }
    let urlParams = {}
    let query = loc.substring(1)

    if (/\?/.test(query)) {
      query = query.split('?')[1]
    }

    while (1) {
      const match = search.exec(query)

      if (!match) {
        break
      }
      urlParams[decode(match[1])] = decode(match[2])
    }

    return urlParams
  }

  authorize (obj = {}) {
    let { redirectUrl, scope } = obj

    window.location = this._loginUrl(redirectUrl || window.location, scope)
  }

  refreshTokenTimer(refreshTime = 15 * 60000) {
    this.silentRefresh = setInterval(async () => {
      const response =  await fetch(this.refreshTokenUrl, {
        method: 'POST',
        credentials: 'include'
      })

      if (response.status === 200) {
        const resp = await response.json()
        if (resp.success) {
          this.storage.setItem('token', resp.idToken)
          this.EventEmitter.emit('accessTokenUpdated', resp.idToken)
        } else {
          throw(new Error('Failed to refresh the token'))
        }
      } else {
        throw(response.err)
      }
    }, refreshTime)
  }

  stopRefreshTimer() {
    clearInterval(this.silentRefresh);
  }

  getUser () {
    let storeUser = this.storage.getItem('user')

    if (this.currentUser) {
      return this.currentUser
    }
    if (storeUser) {
      return JSON.parse(storeUser)
    }
    return undefined
  }

  checkToken (loc = window.location.search) {
    let params = this._parseQueryString(loc)
    let self = this

    self.token = params.token || params.access_token || this.storage.getItem('token') || undefined

    return new Promise((resolve, reject) => {
      if (self.isAuthenticated() && self.token && typeof self.token !== 'undefined') {
        resolve(self.getUser())
      }

      if (self.token && typeof self.token !== 'undefined') {
        if (window) {
          window.history.replaceState({}, '', window.location.pathname + window.location.hash || '')
        }
        self.storage.setItem('token', self.token)
        self.fetchUser(this.userFetchUrl)
          .then((user) => {
            resolve(user)
          })
          .catch((err) => {
            reject(err)
          })
      } else {
        reject(new Error('access token not found'))
      }
    })
  }

  checkAccess (productIds = []) {
    const token = this.token || this.storage.getItem('token') || undefined
    const products = Array.isArray(productIds) ? productIds : [productIds]
    const user = this.getUser()

    return new Promise(async (resolve, reject) => {
      if (token && typeof token !== 'undefined') {
        try {
          const allowedProducts = await this.fetchAccess(this.accessCheckUrl, { productIds: products })
          resolve({ success: true, user: user, products: allowedProducts })
        } catch (err) {
          reject(err)
        }
      } else {
        reject(new Error('access token not found'))
      }
    })
  }

  fetchUser (url) {
    let self = this

    return new Promise(async (resolve, reject) => {
      const response = await fetch(url, {
        method: 'GET',
        mode: 'cors',
        headers: {
          'Content-Type': 'application/json',
          'X-Access-Token': self.token || this.storage.getItem('token')
        }
      })

      if (response.status === 200) {
        const resp = await response.json()
        const user = resp.user || resp.objects[0]

        self.storage.setItem('user', JSON.stringify(user))
        resolve(user)
      } else {
        reject(new Error('authentication failed: Invalid response'))
      }
    })
  }

  fetchAccess (url, body) {
    const self = this

    return new Promise(async (resolve, reject) => {
      const response = await fetch(url, {
        method: 'POST',
        mode: 'cors',
        cache: 'no-cache',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json',
          'X-Access-Token': self.token || this.storage.getItem('token')
        },
        body: JSON.stringify(body)
      })

      if (response.status === 200) {
        const resp = await response.json()
        if (resp.success) {
          resolve(resp.products)
        } else {
          reject(new Error('This user does not have access to this product'))
        }
      } else if (response.status === 401) {
        reject(new Error('access token not found'))
      } else {
        reject(new Error('invalid response from server'))
      }
    })
  }

  async logout (url) {
    this.storage.removeItem('user')
    this.storage.removeItem('token')
    this.stopRefreshTimer()

    url = url || this.logoutUrl

    if (url) window.location = url
  }

  isAuthenticated () {
    let user = this.getUser()

    if (user) {
      return true
    }
    return false
  }
}
<|endoftext|>


<commit_before>dojo.provide("dijit.Tooltip");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

dojo.declare(
	"dijit._MasterTooltip",
	[dijit._Widget, dijit._Templated],
	{
		// summary
		//		Internal widget that holds the actual tooltip markup,
		//		which occurs once per page.
		//		Called by Tooltip widgets which are just containers to hold
		//		the markup

		// duration: Integer
		//		Milliseconds to fade in/fade out
		duration: dijit.defaultDuration,

		templatePath: dojo.moduleUrl("dijit", "templates/Tooltip.html"),

		postCreate: function(){
			dojo.body().appendChild(this.domNode);

			this.bgIframe = new dijit.BackgroundIframe(this.domNode);

			// Setup fade-in and fade-out functions.
			this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
			this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });

		},

		show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){
			// summary:
			//	Display tooltip w/specified contents to right specified node
			//	(To left if there's no space on the right, or if LTR==right)

			if(this.aroundNode && this.aroundNode === aroundNode){
				return;
			}

			if(this.fadeOut.status() == "playing"){
				// previous tooltip is being hidden; wait until the hide completes then show new one
				this._onDeck=arguments;
				return;
			}
			this.containerNode.innerHTML=innerHTML;

			// Firefox bug. when innerHTML changes to be shorter than previous
			// one, the node size will not be updated until it moves.
			this.domNode.style.top = (this.domNode.offsetTop + 1) + "px";

			// position the element and change CSS according to position[] (a list of positions to try)
			var align = {};
			var ltr = this.isLeftToRight();
			dojo.forEach( (position && position.length) ? position : dijit.Tooltip.defaultPosition, function(pos){
				switch(pos){
					case "after":
						align[ltr ? "BR" : "BL"] = ltr ? "BL" : "BR";
						break;
					case "before":
						align[ltr ? "BL" : "BR"] = ltr ? "BR" : "BL";
						break;
					case "below":
						// first try to align left borders, next try to align right borders (or reverse for RTL mode)
						align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR";
						align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL";
						break;
					case "above":
					default:
						// first try to align left borders, next try to align right borders (or reverse for RTL mode)
						align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR";
						align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL";
						break;
				}
			});
			var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, align, dojo.hitch(this, "orient"));

			// show it
			dojo.style(this.domNode, "opacity", 0);
			this.fadeIn.play();
			this.isShowingNow = true;
			this.aroundNode = aroundNode;
		},

		orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
			// summary: private function to set CSS for tooltip node based on which position it's in
			node.className = "dijitTooltip " +
				{
					"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
					"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
					"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
					"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
					"BR-BL": "dijitTooltipRight",
					"BL-BR": "dijitTooltipLeft"
				}[aroundCorner + "-" + tooltipCorner];
		},

		_onShow: function(){
			if(dojo.isIE){
				// the arrow won't show up on a node w/an opacity filter
				this.domNode.style.filter="";
			}
		},

		hide: function(aroundNode){
			// summary: hide the tooltip
			if(!this.aroundNode || this.aroundNode !== aroundNode){
				return;
			}
			if(this._onDeck){
				// this hide request is for a show() that hasn't even started yet;
				// just cancel the pending show()
				this._onDeck=null;
				return;
			}
			this.fadeIn.stop();
			this.isShowingNow = false;
			this.aroundNode = null;
			this.fadeOut.play();
		},

		_onHide: function(){
			this.domNode.style.cssText="";	// to position offscreen again
			if(this._onDeck){
				// a show request has been queued up; do it now
				this.show.apply(this, this._onDeck);
				this._onDeck=null;
			}
		}

	}
);

dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){
	// summary:
	//	Display tooltip w/specified contents in specified position.
	//	See description of dijit.Tooltip.defaultPosition for details on position parameter.
	//	If position is not specified then dijit.Tooltip.defaultPosition is used.
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.show(innerHTML, aroundNode, position);
};

dijit.hideTooltip = function(aroundNode){
	// summary: hide the tooltip
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.hide(aroundNode);
};

dojo.declare(
	"dijit.Tooltip",
	dijit._Widget,
	{
		// summary
		//		Pops up a tooltip (a help message) when you hover over a node.

		// label: String
		//		Text to display in the tooltip.
		//		Specified as innerHTML when creating the widget from markup.
		label: "",

		// showDelay: Integer
		//		Number of milliseconds to wait after hovering over/focusing on the object, before
		//		the tooltip is displayed.
		showDelay: 400,

		// connectId: String[]
		//		Id(s) of domNodes to attach the tooltip to.
		//		When user hovers over any of the specified dom nodes, the tooltip will appear.
		connectId: [],

		//	position: String[]
		//		See description of dijit.Tooltip.defaultPosition for details on position parameter.
		position: [],

		postCreate: function(){

			dojo.addClass(this.domNode,"dijitTooltipData");

			this._connectNodes = [];

			dojo.forEach(this.connectId, function(id) {
				var node = dojo.byId(id);
				if (node) {
					this._connectNodes.push(node);
					dojo.forEach(["onMouseEnter", "onMouseLeave", "onFocus", "onBlur"], function(event){
						this.connect(node, event.toLowerCase(), "_"+event);
					}, this);
					if(dojo.isIE){
						// BiDi workaround
						node.style.zoom = 1;
					}
				}
			}, this);
		},

		_onMouseEnter: function(/*Event*/ e){
			this._onHover(e);
		},

		_onMouseLeave: function(/*Event*/ e){
			this._onUnHover(e);
		},

		_onFocus: function(/*Event*/ e){
			this._focus = true;
			this._onHover(e);
			this.inherited(arguments);
		},

		_onBlur: function(/*Event*/ e){
			this._focus = false;
			this._onUnHover(e);
			this.inherited(arguments);
		},

		_onHover: function(/*Event*/ e){
			if(!this._showTimer){
				var target = e.target;
				this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
			}
		},

		_onUnHover: function(/*Event*/ e){
			// keep a tooltip open if the associated element has focus
			if(this._focus){ return; }
			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			this.close();
		},

		open: function(/*DomNode*/ target){
 			// summary: display the tooltip; usually not called directly.
			target = target || this._connectNodes[0];
			if(!target){ return; }

			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position);

			this._connectNode = target;
		},

		close: function(){
			// summary: hide the tooltip; usually not called directly.
			dijit.hideTooltip(this._connectNode);
			delete this._connectNode;
			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
		},

		uninitialize: function(){
			this.close();
		}
	}
);

// dijit.Tooltip.defaultPosition: String[]
//		This variable controls the position of tooltips, if the position is not specified to
//		the Tooltip widget or *TextBox widget itself.  It's an array of strings with the following values:
//
//			* before: places tooltip to the left of the target node/widget, or to the right in
//			  the case of RTL scripts like Hebrew and Arabic
//			* after: places tooltip to the right of the target node/widget, or to the left in
//			  the case of RTL scripts like Hebrew and Arabic
//			* above: tooltip goes above target node
//			* below: tooltip goes below target node
//
//		The list is positions is tried, in order, until a position is found where the tooltip fits
//		within the viewport.
//
//		Be careful setting this parameter.  A value of "above" may work fine until the user scrolls
//		the screen so that there's no room above the target node.   Nodes with drop downs, like
//		DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
//		that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
//		is only room below (or above) the target node, but not both.
dijit.Tooltip.defaultPosition = ["after", "before"];<commit_msg>Fixes #7361: race condition leading to tooltip remaining shown when it shouldn't have appeared/should have been erased:   1. tooltipA is being shown   2. hide() is called for tooltipA; tooltipA starts to fade out   3. show() is called for tooltipB; tooltipB is put onDeck   4. hide() is called for tooltipB (while it's still onDeck)   5. tooltipB is shown<commit_after>dojo.provide("dijit.Tooltip");

dojo.require("dijit._Widget");
dojo.require("dijit._Templated");

dojo.declare(
	"dijit._MasterTooltip",
	[dijit._Widget, dijit._Templated],
	{
		// summary
		//		Internal widget that holds the actual tooltip markup,
		//		which occurs once per page.
		//		Called by Tooltip widgets which are just containers to hold
		//		the markup

		// duration: Integer
		//		Milliseconds to fade in/fade out
		duration: dijit.defaultDuration,

		templatePath: dojo.moduleUrl("dijit", "templates/Tooltip.html"),

		postCreate: function(){
			dojo.body().appendChild(this.domNode);

			this.bgIframe = new dijit.BackgroundIframe(this.domNode);

			// Setup fade-in and fade-out functions.
			this.fadeIn = dojo.fadeIn({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onShow") });
			this.fadeOut = dojo.fadeOut({ node: this.domNode, duration: this.duration, onEnd: dojo.hitch(this, "_onHide") });

		},

		show: function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){
			// summary:
			//	Display tooltip w/specified contents to right specified node
			//	(To left if there's no space on the right, or if LTR==right)

			if(this.aroundNode && this.aroundNode === aroundNode){
				return;
			}

			if(this.fadeOut.status() == "playing"){
				// previous tooltip is being hidden; wait until the hide completes then show new one
				this._onDeck=arguments;
				return;
			}
			this.containerNode.innerHTML=innerHTML;

			// Firefox bug. when innerHTML changes to be shorter than previous
			// one, the node size will not be updated until it moves.
			this.domNode.style.top = (this.domNode.offsetTop + 1) + "px";

			// position the element and change CSS according to position[] (a list of positions to try)
			var align = {};
			var ltr = this.isLeftToRight();
			dojo.forEach( (position && position.length) ? position : dijit.Tooltip.defaultPosition, function(pos){
				switch(pos){
					case "after":
						align[ltr ? "BR" : "BL"] = ltr ? "BL" : "BR";
						break;
					case "before":
						align[ltr ? "BL" : "BR"] = ltr ? "BR" : "BL";
						break;
					case "below":
						// first try to align left borders, next try to align right borders (or reverse for RTL mode)
						align[ltr ? "BL" : "BR"] = ltr ? "TL" : "TR";
						align[ltr ? "BR" : "BL"] = ltr ? "TR" : "TL";
						break;
					case "above":
					default:
						// first try to align left borders, next try to align right borders (or reverse for RTL mode)
						align[ltr ? "TL" : "TR"] = ltr ? "BL" : "BR";
						align[ltr ? "TR" : "TL"] = ltr ? "BR" : "BL";
						break;
				}
			});
			var pos = dijit.placeOnScreenAroundElement(this.domNode, aroundNode, align, dojo.hitch(this, "orient"));

			// show it
			dojo.style(this.domNode, "opacity", 0);
			this.fadeIn.play();
			this.isShowingNow = true;
			this.aroundNode = aroundNode;
		},

		orient: function(/* DomNode */ node, /* String */ aroundCorner, /* String */ tooltipCorner){
			// summary: private function to set CSS for tooltip node based on which position it's in
			node.className = "dijitTooltip " +
				{
					"BL-TL": "dijitTooltipBelow dijitTooltipABLeft",
					"TL-BL": "dijitTooltipAbove dijitTooltipABLeft",
					"BR-TR": "dijitTooltipBelow dijitTooltipABRight",
					"TR-BR": "dijitTooltipAbove dijitTooltipABRight",
					"BR-BL": "dijitTooltipRight",
					"BL-BR": "dijitTooltipLeft"
				}[aroundCorner + "-" + tooltipCorner];
		},

		_onShow: function(){
			if(dojo.isIE){
				// the arrow won't show up on a node w/an opacity filter
				this.domNode.style.filter="";
			}
		},

		hide: function(aroundNode){
			// summary: hide the tooltip
			if(this._onDeck && this._onDeck[1] == aroundNode){
				// this hide request is for a show() that hasn't even started yet;
				// just cancel the pending show()
				this._onDeck=null;
			}else if(this.aroundNode === aroundNode){
				// this hide request is for the currently displayed tooltip
				this.fadeIn.stop();
				this.isShowingNow = false;
				this.aroundNode = null;
				this.fadeOut.play();
			}else{
				// just ignore the call, it's for a tooltip that has already been erased
			}
		},

		_onHide: function(){
			this.domNode.style.cssText="";	// to position offscreen again
			if(this._onDeck){
				// a show request has been queued up; do it now
				this.show.apply(this, this._onDeck);
				this._onDeck=null;
			}
		}

	}
);

dijit.showTooltip = function(/*String*/ innerHTML, /*DomNode*/ aroundNode, /*String[]?*/ position){
	// summary:
	//	Display tooltip w/specified contents in specified position.
	//	See description of dijit.Tooltip.defaultPosition for details on position parameter.
	//	If position is not specified then dijit.Tooltip.defaultPosition is used.
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.show(innerHTML, aroundNode, position);
};

dijit.hideTooltip = function(aroundNode){
	// summary: hide the tooltip
	if(!dijit._masterTT){ dijit._masterTT = new dijit._MasterTooltip(); }
	return dijit._masterTT.hide(aroundNode);
};

dojo.declare(
	"dijit.Tooltip",
	dijit._Widget,
	{
		// summary
		//		Pops up a tooltip (a help message) when you hover over a node.

		// label: String
		//		Text to display in the tooltip.
		//		Specified as innerHTML when creating the widget from markup.
		label: "",

		// showDelay: Integer
		//		Number of milliseconds to wait after hovering over/focusing on the object, before
		//		the tooltip is displayed.
		showDelay: 400,

		// connectId: String[]
		//		Id(s) of domNodes to attach the tooltip to.
		//		When user hovers over any of the specified dom nodes, the tooltip will appear.
		connectId: [],

		//	position: String[]
		//		See description of dijit.Tooltip.defaultPosition for details on position parameter.
		position: [],

		postCreate: function(){

			dojo.addClass(this.domNode,"dijitTooltipData");

			this._connectNodes = [];

			dojo.forEach(this.connectId, function(id) {
				var node = dojo.byId(id);
				if (node) {
					this._connectNodes.push(node);
					dojo.forEach(["onMouseEnter", "onMouseLeave", "onFocus", "onBlur"], function(event){
						this.connect(node, event.toLowerCase(), "_"+event);
					}, this);
					if(dojo.isIE){
						// BiDi workaround
						node.style.zoom = 1;
					}
				}
			}, this);
		},

		_onMouseEnter: function(/*Event*/ e){
			this._onHover(e);
		},

		_onMouseLeave: function(/*Event*/ e){
			this._onUnHover(e);
		},

		_onFocus: function(/*Event*/ e){
			this._focus = true;
			this._onHover(e);
			this.inherited(arguments);
		},

		_onBlur: function(/*Event*/ e){
			this._focus = false;
			this._onUnHover(e);
			this.inherited(arguments);
		},

		_onHover: function(/*Event*/ e){
			if(!this._showTimer){
				var target = e.target;
				this._showTimer = setTimeout(dojo.hitch(this, function(){this.open(target)}), this.showDelay);
			}
		},

		_onUnHover: function(/*Event*/ e){
			// keep a tooltip open if the associated element has focus
			if(this._focus){ return; }
			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			this.close();
		},

		open: function(/*DomNode*/ target){
 			// summary: display the tooltip; usually not called directly.
			target = target || this._connectNodes[0];
			if(!target){ return; }

			if(this._showTimer){
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
			dijit.showTooltip(this.label || this.domNode.innerHTML, target, this.position);

			this._connectNode = target;
		},

		close: function(){
			// summary: hide the tooltip or cancel timer for show of tooltip
			if(this._connectNode){
				// if tooltip is currently shown
				dijit.hideTooltip(this._connectNode);
				delete this._connectNode;
			}
			if(this._showTimer){
				// if tooltip is scheduled to be shown (after a brief delay)
				clearTimeout(this._showTimer);
				delete this._showTimer;
			}
		},

		uninitialize: function(){
			this.close();
		}
	}
);

// dijit.Tooltip.defaultPosition: String[]
//		This variable controls the position of tooltips, if the position is not specified to
//		the Tooltip widget or *TextBox widget itself.  It's an array of strings with the following values:
//
//			* before: places tooltip to the left of the target node/widget, or to the right in
//			  the case of RTL scripts like Hebrew and Arabic
//			* after: places tooltip to the right of the target node/widget, or to the left in
//			  the case of RTL scripts like Hebrew and Arabic
//			* above: tooltip goes above target node
//			* below: tooltip goes below target node
//
//		The list is positions is tried, in order, until a position is found where the tooltip fits
//		within the viewport.
//
//		Be careful setting this parameter.  A value of "above" may work fine until the user scrolls
//		the screen so that there's no room above the target node.   Nodes with drop downs, like
//		DropDownButton or FilteringSelect, are especially problematic, in that you need to be sure
//		that the drop down and tooltip don't overlap, even when the viewport is scrolled so that there
//		is only room below (or above) the target node, but not both.
dijit.Tooltip.defaultPosition = ["after", "before"];<|endoftext|>


<commit_before>#!/usr/bin/env node
/*
 * Copyright (c) 2011 Joyent Inc., All rights reserved.
 *
 * Simple DHCP server daemon.
 *
 */

var dgram = require('dgram'),
     slog = require('sys').log,
       fs = require('fs'),
     dhcp = require('./lib/dhcp'),
  menulst = require('./lib/menulst'),
     Mapi = require('./lib/mapi').Mapi,
  sprintf = require('./lib/sprintf'),
   config = require('./config').config;

var SERVER_HOST = config.listenIp;
var DHCP_HOST   = config.dhcpIp;
var DEFAULT_GW  = config.defaultGateway || "";
var SERVER_PORT = 67;
var TFTPROOT    = config.tftpRoot;
var LEASE_TIME  = config.leaseTime;
var NETMASK     = config.netmask;

var sessions = {};
var sock = null;
var mapi = new Mapi();

function build_packet_opts(key, msg_type) {
    var response_type = msg_type == 'DHCPDISCOVER' ? 'DHCPOFFER' : 'DHCPACK';

    slog(key + "< " + msg_type);

    var packet_opts = {
        'siaddr': DHCP_HOST
      , 'file': 'pxegrub'
      , 'options':
        { '1': NETMASK
        , '51': LEASE_TIME
        , '53': response_type
        , '54': DHCP_HOST
        }
    };
    if (DEFAULT_GW != "") {
        packet_opts['options']['3']=DEFAULT_GW;
    }

    slog(key + "> " + response_type);
    return packet_opts;
}

sock = dgram.createSocket("udp4", function (msg, peer) {
    var in_packet = dhcp.DHCPPacket.parse(msg);
    var key = "[" + in_packet.chaddr + "] ";
    slog(key + "src_address=" + peer.address + ":" + peer.port);

    // Print the whole packet in hex
    if (0) {
        for(var i=0; i<msg.length; i+=4) {
            slog(sprintf.sprintf("[%03d]: 0x%02x 0x%02x 0x%02x 0x%02x", i, msg[i], msg[i+1], msg[i+2], msg[i+3]));
        }
    }

    in_packet.dump(function (msg) {
      slog(key + msg);
    });

    // decide what to do based on message type (option 53)
    var msg_type = dhcp.DHCP_MESSAGE_TYPE[in_packet.options[53]];
    switch (msg_type) {
        case 'DHCPDISCOVER':
        case 'DHCPREQUEST':
            packet_opts = build_packet_opts(key, msg_type);
            break;
        default:
            slog(key + "< " + msg_type + ": not responding");
            return;
            break;
    }

    mapi.getBootParams(in_packet.chaddr, peer.address, function(params) {
      if (params == null) {
        slog(key + "No config returned from MAPI. Not sending reply");
        return;
      }

      menulst.writeMenuLst(in_packet.chaddr, params, TFTPROOT, function(err) {
        if (err) {
          slog(key + "Error writing menu.lst. Not sending reply");
          return;
        }

        packet_opts['yiaddr'] = params.ip;
        packet_opts.options['1'] = params.netmask;

        out_packet = dhcp.DHCPPacket.build_reply(in_packet, packet_opts);
        var out = out_packet.raw();
        res = sock.send(out, 0, out.length, 68, '255.255.255.255', function (err, bytes) {
            if (err) throw err;
            slog(key + "Wrote " + bytes + " bytes to socket.");
        });

        out_packet.dump(function (msg) {
            slog(key + msg);
        });

      });
    });
});

sock.on('listening', function() {
    sock.setTTL(128);  // XXX Doesn't work! :( Bug in node?
    sock.setBroadcast(true);
    slog('Bound to '+ SERVER_HOST + ':' + SERVER_PORT);
});
sock.bind(SERVER_PORT, SERVER_HOST);

<commit_msg>[NET-165] booter should send DNS resolvers to compute nodes in DHCP reply<commit_after>#!/usr/bin/env node
/*
 * Copyright (c) 2011 Joyent Inc., All rights reserved.
 *
 * Simple DHCP server daemon.
 *
 */

var dgram = require('dgram'),
     slog = require('sys').log,
       fs = require('fs'),
     dhcp = require('./lib/dhcp'),
  menulst = require('./lib/menulst'),
     Mapi = require('./lib/mapi').Mapi,
  sprintf = require('./lib/sprintf'),
   config = require('./config').config;

var SERVER_HOST = config.listenIp;
var DHCP_HOST   = config.dhcpIp;
var DEFAULT_GW  = config.defaultGateway || "";
var SERVER_PORT = 67;
var TFTPROOT    = config.tftpRoot;
var LEASE_TIME  = config.leaseTime;
var NETMASK     = config.netmask;

var sessions = {};
var sock = null;
var mapi = new Mapi();

function build_packet_opts(key, msg_type) {
    var response_type = msg_type == 'DHCPDISCOVER' ? 'DHCPOFFER' : 'DHCPACK';

    slog(key + "< " + msg_type);

    var packet_opts = {
        'siaddr': DHCP_HOST
      , 'file': 'pxegrub'
      , 'options':
        { '1': NETMASK
        , '51': LEASE_TIME
        , '53': response_type
        , '54': DHCP_HOST
        }
    };
    if (DEFAULT_GW != "") {
        packet_opts['options']['3']=DEFAULT_GW;
    }

    slog(key + "> " + response_type);
    return packet_opts;
}

sock = dgram.createSocket("udp4", function (msg, peer) {
    var in_packet = dhcp.DHCPPacket.parse(msg);
    var key = "[" + in_packet.chaddr + "] ";
    slog(key + "src_address=" + peer.address + ":" + peer.port);

    // Print the whole packet in hex
    if (0) {
        for(var i=0; i<msg.length; i+=4) {
            slog(sprintf.sprintf("[%03d]: 0x%02x 0x%02x 0x%02x 0x%02x", i, msg[i], msg[i+1], msg[i+2], msg[i+3]));
        }
    }

    in_packet.dump(function (msg) {
      slog(key + msg);
    });

    // decide what to do based on message type (option 53)
    var msg_type = dhcp.DHCP_MESSAGE_TYPE[in_packet.options[53]];
    switch (msg_type) {
        case 'DHCPDISCOVER':
        case 'DHCPREQUEST':
            packet_opts = build_packet_opts(key, msg_type);
            break;
        default:
            slog(key + "< " + msg_type + ": not responding");
            return;
            break;
    }

    mapi.getBootParams(in_packet.chaddr, peer.address, function(params) {
      if (params == null) {
        slog(key + "No config returned from MAPI. Not sending reply");
        return;
      }

      menulst.writeMenuLst(in_packet.chaddr, params, TFTPROOT, function(err) {
        if (err) {
          slog(key + "Error writing menu.lst. Not sending reply");
          return;
        }

        packet_opts['yiaddr'] = params.ip;
        packet_opts.options['1'] = params.netmask;
        if (params.resolvers && params.resolvers.length) {
          packet_opts.options['6'] = params.resolvers;
        }

        out_packet = dhcp.DHCPPacket.build_reply(in_packet, packet_opts);
        var out = out_packet.raw();
        res = sock.send(out, 0, out.length, 68, '255.255.255.255', function (err, bytes) {
            if (err) throw err;
            slog(key + "Wrote " + bytes + " bytes to socket.");
        });

        out_packet.dump(function (msg) {
            slog(key + msg);
        });

      });
    });
});

sock.on('listening', function() {
    sock.setTTL(128);  // XXX Doesn't work! :( Bug in node?
    sock.setBroadcast(true);
    slog('Bound to '+ SERVER_HOST + ':' + SERVER_PORT);
});
sock.bind(SERVER_PORT, SERVER_HOST);

<|endoftext|>


<commit_before>// Export widget models and views, and the npm package version number.
module.exports = require('./main.js');
module.exports['version'] = require('../package.json').version;
<commit_msg>Fixed missing reference to json file<commit_after>// Export widget models and views, and the npm package version number.
module.exports = require('./main.js');
module.exports['version'] = '0.1.0';
<|endoftext|>