<commit_before>var Lang = A.Lang,

    ACTIVE_INPUT = 'activeInput',
    AUTO = 'auto',
    AUTO_HIDE = 'autoHide',
    AUTOCOMPLETE = 'autocomplete',
    DATE_SEPARATOR = 'dateSeparator',
    MASK = 'mask',
    SELECT = 'select',
    SELECTION_CHANGE = 'selectionChange',
    TRIGGER = 'trigger',
    VALUES = 'values';

function TimePickerBase() {}

TimePickerBase.ATTRS = {
    autocomplete: {
        setter: '_setAutocomplete',
        value: {},
        writeOnce: true
    },

    dateSeparator: {
        value: ', '
    },

    mask: {
        value: '%I:%M %p'
    },

    popoverCssClass: {
        value: A.getClassName('timepicker-popover')
    },

    values: {
        setter: '_setValues',
        value: [
            '00:00',
            '00:30',
            '01:00',
            '01:30',
            '02:00',
            '02:30',
            '03:00',
            '03:30',
            '04:00',
            '04:30',
            '05:00',
            '05:30',
            '06:00',
            '06:30',
            '07:00',
            '07:30',
            '08:00',
            '08:30',
            '09:00',
            '09:30',
            '10:00',
            '10:30',
            '11:00',
            '11:30',
            '12:00',
            '12:30',
            '13:00',
            '13:30',
            '14:00',
            '14:30',
            '15:00',
            '15:30',
            '16:00',
            '16:30',
            '17:00',
            '17:30',
            '18:00',
            '18:30',
            '19:00',
            '19:30',
            '20:00',
            '20:30',
            '21:00',
            '21:30',
            '22:00',
            '22:30',
            '23:00',
            '23:30'
        ],
        validator: Lang.isArray
    }
};

A.mix(TimePickerBase.prototype, {
    autocomplete: null,

    clearSelection: function() {
        var instance = this;

        instance._handleSelection();
    },

    getAutoComplete: function(node) {
        var instance = this,
            autocomplete = instance.autocomplete,
            autocompleteConfig = instance.get(AUTOCOMPLETE);

        if (autocomplete) {
            autocomplete.destroy();
        }

        autocompleteConfig.inputNode = node;
        autocomplete = new A.AutoComplete(autocompleteConfig);
        autocomplete.render(instance.getPopover().bodyNode).sendRequest();
        instance.autocomplete = autocomplete;

        autocomplete.after(SELECT, instance._afterAutocompleteSelect, instance);

        return autocomplete;
    },

    selectDates: function(dates) {
        var instance = this;

        instance._handleSelection(dates);
    },

    useInputNode: function(node) {
        var instance = this,
            activeInput = instance.get(ACTIVE_INPUT),
            popover = instance.getPopover();

        if (activeInput !== node) {
            instance.set(ACTIVE_INPUT, node);
            popover.set(TRIGGER, node);
            instance.getAutoComplete(node);
        }

        instance.alignTo(node);
        instance.selectDates(instance.getParsedDatesFromInputValue());
    },

    _afterAutocompleteSelect: function(event) {
        var instance = this,
            parsed = instance.getParsedDatesFromInputValue(),
            selected = instance.getParsedDatesFromInputValue(event.result.raw);

        if (parsed.length && selected.length) {
            parsed.pop();
            parsed.push(selected.pop());
        }

        instance.selectDates(parsed);

        if (instance.get(AUTO_HIDE)) {
            instance.hide();
        }
    },

    _handleSelection: function(selection) {
        var instance = this;

        if (selection) {
            instance.fire(SELECTION_CHANGE, { newSelection: selection });
        }
    },

    _setAutocomplete: function(val) {
        var instance = this,
            dateSeparator = instance.get(DATE_SEPARATOR),
            values = instance.get(VALUES);

        return A.merge({
            align: false,
            allowTrailingDelimiter: true,
            alwaysShowList: true,
            minQueryLength: 0,
            queryDelimiter: dateSeparator,
            source: values,
            tabSelect: false,
            width: AUTO
        }, val);
    },

    _setValues: function(val) {
        var instance = this,
            formatted = [];

        A.Array.each(val, function(timeISOFormat) {
            formatted.push(
                A.Date.format(
                    A.Date.parse('%H:%M', timeISOFormat),
                    { format: instance.get(MASK) }));
        });

        return formatted;
    }
}, true);

A.TimePickerBase = TimePickerBase;

A.TimePicker = A.Base.create('timepicker', A.Base, [A.DatePickerDelegate, A.DatePickerPopover, A.TimePickerBase]);<commit_msg>Add API Docs placeholder for TimePicker<commit_after>/**
 * The TimePicker Component
 *
 * @module aui-timepicker
 */

var Lang = A.Lang,

    ACTIVE_INPUT = 'activeInput',
    AUTO = 'auto',
    AUTO_HIDE = 'autoHide',
    AUTOCOMPLETE = 'autocomplete',
    DATE_SEPARATOR = 'dateSeparator',
    MASK = 'mask',
    SELECT = 'select',
    SELECTION_CHANGE = 'selectionChange',
    TRIGGER = 'trigger',
    VALUES = 'values';

/**
 * A base class for TimePickerBase.
 *
 * @class A.TimePickerBase
 * @param config {Object} Object literal specifying widget configuration properties.
 * @constructor
 */
function TimePickerBase() {}

/**
 * Static property used to define the default attribute
 * configuration for the TimePickerBase.
 *
 * @property TimePickerBase.ATTRS
 * @type Object
 * @static
 */
TimePickerBase.ATTRS = {

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute autocomplete
     * @default {}
     * @writeOnce
     */
    autocomplete: {
        setter: '_setAutocomplete',
        value: {},
        writeOnce: true
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute dateSeparator
     * @default ', '
     */
    dateSeparator: {
        value: ', '
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute mask
     * @default '%I:%M %p'
     */
    mask: {
        value: '%I:%M %p'
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute popoverCssClass
     * @default A.getClassName('timepicker-popover')
     */
    popoverCssClass: {
        value: A.getClassName('timepicker-popover')
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @attribute values
     * @default ['00:00', '00:30', '01:00', '01:30', '02:00', '02:30', '03:00', '03:30', '04:00', '04:30', '05:00', '05:30', '06:00', '06:30', '07:00', '07:30', '08:00', '08:30', '09:00', '09:30', '10:00', '10:30', '11:00', '11:30', '12:00', '12:30', '13:00', '13:30', '14:00', '14:30', '15:00', '15:30', '16:00', '16:30', '17:00', '17:30', '18:00', '18:30', '19:00', '19:30', '20:00', '20:30', '21:00', '21:30', '22:00', '22:30', '23:00', '23:30']
     * @type Array
     */
    values: {
        setter: '_setValues',
        value: [
            '00:00',
            '00:30',
            '01:00',
            '01:30',
            '02:00',
            '02:30',
            '03:00',
            '03:30',
            '04:00',
            '04:30',
            '05:00',
            '05:30',
            '06:00',
            '06:30',
            '07:00',
            '07:30',
            '08:00',
            '08:30',
            '09:00',
            '09:30',
            '10:00',
            '10:30',
            '11:00',
            '11:30',
            '12:00',
            '12:30',
            '13:00',
            '13:30',
            '14:00',
            '14:30',
            '15:00',
            '15:30',
            '16:00',
            '16:30',
            '17:00',
            '17:30',
            '18:00',
            '18:30',
            '19:00',
            '19:30',
            '20:00',
            '20:30',
            '21:00',
            '21:30',
            '22:00',
            '22:30',
            '23:00',
            '23:30'
        ],
        validator: Lang.isArray
    }
};

A.mix(TimePickerBase.prototype, {
    autocomplete: null,

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method clearSelection
     */
    clearSelection: function() {
        var instance = this;

        instance._handleSelection();
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method getAutoComplete
     * @param node
     */
    getAutoComplete: function(node) {
        var instance = this,
            autocomplete = instance.autocomplete,
            autocompleteConfig = instance.get(AUTOCOMPLETE);

        if (autocomplete) {
            autocomplete.destroy();
        }

        autocompleteConfig.inputNode = node;
        autocomplete = new A.AutoComplete(autocompleteConfig);
        autocomplete.render(instance.getPopover().bodyNode).sendRequest();
        instance.autocomplete = autocomplete;

        autocomplete.after(SELECT, instance._afterAutocompleteSelect, instance);

        return autocomplete;
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method selectDates
     * @param dates
     */
    selectDates: function(dates) {
        var instance = this;

        instance._handleSelection(dates);
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method useInputNode
     * @param node
     */
    useInputNode: function(node) {
        var instance = this,
            activeInput = instance.get(ACTIVE_INPUT),
            popover = instance.getPopover();

        if (activeInput !== node) {
            instance.set(ACTIVE_INPUT, node);
            popover.set(TRIGGER, node);
            instance.getAutoComplete(node);
        }

        instance.alignTo(node);
        instance.selectDates(instance.getParsedDatesFromInputValue());
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _afterAutocompleteSelect
     * @param event
     * @protected
     */
    _afterAutocompleteSelect: function(event) {
        var instance = this,
            parsed = instance.getParsedDatesFromInputValue(),
            selected = instance.getParsedDatesFromInputValue(event.result.raw);

        if (parsed.length && selected.length) {
            parsed.pop();
            parsed.push(selected.pop());
        }

        instance.selectDates(parsed);

        if (instance.get(AUTO_HIDE)) {
            instance.hide();
        }
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _handleSelection
     * @param selection
     * @protected
     */
    _handleSelection: function(selection) {
        var instance = this;

        if (selection) {
            instance.fire(SELECTION_CHANGE, { newSelection: selection });
        }
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _setAutocomplete
     * @param val
     * @protected
     */
    _setAutocomplete: function(val) {
        var instance = this,
            dateSeparator = instance.get(DATE_SEPARATOR),
            values = instance.get(VALUES);

        return A.merge({
            align: false,
            allowTrailingDelimiter: true,
            alwaysShowList: true,
            minQueryLength: 0,
            queryDelimiter: dateSeparator,
            source: values,
            tabSelect: false,
            width: AUTO
        }, val);
    },

    /**
     * TODO. Wanna help? Please send a Pull Request.
     *
     * @method _setValues
     * @param val
     * @protected
     */
    _setValues: function(val) {
        var instance = this,
            formatted = [];

        A.Array.each(val, function(timeISOFormat) {
            formatted.push(
                A.Date.format(
                    A.Date.parse('%H:%M', timeISOFormat),
                    { format: instance.get(MASK) }));
        });

        return formatted;
    }
}, true);

A.TimePickerBase = TimePickerBase;

/**
 * A base class for TimePicker.
 *
 * @class A.TimePicker
 * @extends A.Base
 * @uses A.DatePickerDelegate, A.DatePickerPopover, A.TimePickerBase
 * @param config {Object} Object literal specifying widget configuration properties.
 * @constructor
 */
A.TimePicker = A.Base.create('timepicker', A.Base, [A.DatePickerDelegate, A.DatePickerPopover, A.TimePickerBase]);<|endoftext|>


<commit_before>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { DropdownButton, MenuItem } from 'react-bootstrap'

import Icon from '../narrative/icon'

import { MainPanelContent, setMainPanelContent } from '../../actions/ui'

// TODO: make menu items configurable via props/config

class AppMenu extends Component {
  static propTypes = {
    setMainPanelContent: PropTypes.func
  }

  render () {
    return (

        <DropdownButton title={(<Icon type='bars' />)} noCaret className='app-menu-button' id='app-menu'>
          <MenuItem onClick={() => {
            this.props.setMainPanelContent(MainPanelContent.ROUTE_VIEWER)
          }}><Icon type='bus' /> Route Viewer</MenuItem>
        </DropdownButton>

    )
  }
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  return {
  }
}

const mapDispatchToProps = {
  setMainPanelContent
}

export default connect(mapStateToProps, mapDispatchToProps)(AppMenu)
<commit_msg>feat(app menu): Add "Start Over" item to app menu<commit_after>import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
import { DropdownButton, MenuItem } from 'react-bootstrap'

import Icon from '../narrative/icon'

import { MainPanelContent, setMainPanelContent } from '../../actions/ui'

// TODO: make menu items configurable via props/config

class AppMenu extends Component {
  static propTypes = {
    setMainPanelContent: PropTypes.func
  }

  render () {
    return (

        <DropdownButton title={(<Icon type='bars' />)} noCaret className='app-menu-button' id='app-menu'>
          <MenuItem onClick={() => {
            window.location.href = '/'
          }}><Icon type='undo' /> Start Over</MenuItem>
          <MenuItem onClick={() => {
            this.props.setMainPanelContent(MainPanelContent.ROUTE_VIEWER)
          }}><Icon type='bus' /> Route Viewer</MenuItem>
        </DropdownButton>

    )
  }
}

// connect to the redux store

const mapStateToProps = (state, ownProps) => {
  return {
  }
}

const mapDispatchToProps = {
  setMainPanelContent
}

export default connect(mapStateToProps, mapDispatchToProps)(AppMenu)
<|endoftext|>


<commit_before>/*
 * Kuzzle, a backend software, self-hostable and ready to use
 * to power modern apps
 *
 * Copyright 2015-2020 Kuzzle
 * mailto: support AT kuzzle.io
 * website: http://kuzzle.io
 *
 * 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
 *
 * https://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.
 */

'use strict';

const fs = require('fs');
const path = require('path');

const Bluebird = require('bluebird');

const { RequestContext } = require('../../api/request');
const Context = require('./context');
const debug = require('../../util/debug')('kuzzle:network:embedded');
const MqttProtocol = require('./protocols/mqttProtocol');
const InternalProtocol = require('./protocols/internalProtocol');
const HttpWsProtocol = require('./protocols/httpwsProtocol');
const Manifest = require('./protocolManifest');
const removeErrorStack = require('./removeErrorStack');
const kerror = require('../../kerror');
const { AccessLogger } = require('./accessLogger');

const networkError = kerror.wrap('network', 'entrypoint');

const DEFAULT_PROTOCOLS = [
  HttpWsProtocol,
  MqttProtocol,
  InternalProtocol,
];

class EntryPoint {
  constructor () {
    this.config = global.kuzzle.config.server;

    this.protocols = new Map();

    this._clients = new Map();

    this.accessLogger = new AccessLogger();

    this.isShuttingDown = false;
  }

  dispatch (event, data) {
    switch (event) {
      case 'notify':
        this._notify(data);
        return;
      case 'broadcast':
        this._broadcast(data);
        return;
      case 'shutdown':
        this.isShuttingDown = true;
        return ;
      default:
        throw networkError.get('unexpected_event', event);
    }
  }

  /**
   * Initializes the InternalProtocol first to allow subscriptions
   * in plugins init() method.
   *
   * @returns {Promise}
   */
  async init () {
    for (const ProtocolClass of DEFAULT_PROTOCOLS) {
      const protocol = new ProtocolClass();

      this.protocols.set(protocol.name, protocol);
    }

    return this.protocols.get('internal').init(this);
  }

  /**
   * Starts the network protocols.
   * Every protocol is listening for request after this call
   *
   * @returns {Promise}
   */
  async startListening () {
    // We need to verify the port ourselves, to make sure Node.js won't open
    // a named pipe if the provided port number is a string
    if (!Number.isInteger(this.config.port)) {
      throw networkError.get('invalid_port', this.config.port);
    }

    await this.accessLogger.init();

    const initPromises = [];

    for (const protocol of this.protocols.values()) {
      // InternalProtocol is already initialized
      if (protocol.initCalled) {
        continue;
      }

      initPromises.push(protocol.init(this)
        .then(enabled => {
          if (! enabled) {
            this.protocols.delete(protocol.name);
          }
        })
      );
    }

    await Bluebird.all(initPromises);

    await this.loadMoreProtocols();
  }

  /**
   * On client subscribing to a channel, dispatch the information
   * to the protocol.
   *
   * @param {string} channel
   * @param {string} connectionId
   */
  joinChannel (channel, connectionId) {
    debug('[server] client "%s" joining channel "%s"', connectionId, channel);

    const client = this._clients.get(connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).joinChannel(channel, connectionId);
    }
    catch (e) {
      global.kuzzle.log.error(`[join] protocol ${client && client.protocol} failed: ${e.message}`);
    }
  }

  leaveChannel (channel, connectionId) {
    debug(
      '[server] connection "%s" leaving channel "%s"',
      connectionId,
      channel);

    const client = this._clients.get(connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).leaveChannel(channel, connectionId);
    }
    catch (e) {
      global.kuzzle.log.error(`[leave channel] protocol ${client && client.protocol} failed: ${e.message}`);
    }
  }

  /**
   * Loads installed protocols in memory
   */
  async loadMoreProtocols () {
    const dir = path.join(__dirname, '../../../protocols/enabled');
    let dirs;

    try {
      dirs = fs.readdirSync(dir);
    }
    catch (e) {
      // ignore if there is no protocols directory
      return;
    }

    dirs = dirs
      .map(d => path.join(dir, d))
      .filter(d => fs.statSync(d).isDirectory());

    await Bluebird.map(dirs, protoDir => {
      const protocol = new (require(protoDir))();
      const manifest = new Manifest(protoDir, protocol);

      manifest.load();

      const initTimeout = global.kuzzle.config.services.common.defaultInitTimeout;

      return Bluebird.resolve()
        .then(() => protocol.init(this, new Context()))
        .catch(error => {
          global.kuzzle.log.error(`Error during "${manifest.name}" protocol init:`);
          throw error;
        })
        .timeout(initTimeout, `Protocol "${manifest.name}" initialization timed out after ${initTimeout}ms. Try to increase the configuration "services.common.defaultInitTimeout".`)
        .then(() => {
          if (this.protocols.has(manifest.name)) {
            throw kerror.get('protocol', 'runtime', 'already_exists', manifest.name);
          }

          this.protocols.set(manifest.name, protocol);
        });
    });
  }

  /**
   * @param {ClientConnection} connection
   * @param {Request} request
   * @param {object} extra
   */
  logAccess (connection, request, extra = null) {
    this.accessLogger.log(connection, request, extra);
  }

  /*
  -----------------------------------------------------------------------
  methods exposed to protocols
  -----------------------------------------------------------------------
  */

  /**
   * @param {ClientConnection} connection
   * @param {Request} request
   * @param cb
   */
  execute (connection, request, cb) {
    if (this.isShuttingDown) {
      debug('Shutting down. Dropping request: %a', request);
      this._isShuttingDownError(connection, request, cb);
      return;
    }

    debug('Funneling request: %a', request);

    global.kuzzle.pipe('funnel:beforeRequestExecution', request)
      .then(() => {
        global.kuzzle.funnel.execute(request, (error, result) => {
          const _res = result || request;

          if (error && !_res.error) {
            _res.setError(error);
          }

          this.logAccess(connection, _res);

          const response = _res.response.toJSON();

          cb(removeErrorStack(response));
        });
      }).catch((err) => {
        request.setError(err);

        this.logAccess(connection, request);

        const response = request.response.toJSON();

        cb(removeErrorStack(response));
      });
  }

  /**
   *
   * @param {ClientConnection} connection
   */
  newConnection (connection) {
    this._clients.set(connection.id, connection);

    global.kuzzle.emit('connection:new', connection);
    global.kuzzle.router.newConnection(new RequestContext({ connection }));
    debug(
      'New connection created: %s (protocol: %s)',
      connection.id,
      connection.protocol);
  }

  /**
   * @param {string} connectionId
   */
  removeConnection (connectionId) {
    const connection = this._clients.get(connectionId);

    if (connection) {
      global.kuzzle.emit('connection:remove', connection);

      global.kuzzle.router.removeConnection(new RequestContext({ connection }));

      this._clients.delete(connectionId);

      debug(
        'Removed connection: %s (protocol: %s)',
        connection.id,
        connection.protocol);
    }
  }

  // --------------------------------------------------------------------

  _broadcast (data) {
    const sanitized = removeErrorStack(data);

    debug('[server] broadcasting data through all protocols: %a', sanitized);

    for (const [name, protocol] of this.protocols.entries()) {
      try {
        protocol.broadcast(sanitized);
      }
      catch (e) {
        global.kuzzle.log.error(`[broadcast] protocol ${name} failed: ${e.message}\n${e.stack}`);
      }
    }
  }

  _isShuttingDownError (connection, request, cb) {
    request.setError(networkError.get('shutting_down'));
    this.logAccess(connection, request);

    cb(removeErrorStack(request.response.toJSON()));
  }

  _notify (data) {
    debug(
      '[server] sending notification to client with connection id "%s": %a',
      data.connectionId,
      data);

    const client = this._clients.get(data.connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).notify(removeErrorStack(data));
    }
    catch (e) {
      global.kuzzle.log.error(`[notify] protocol ${client.protocol} failed: ${e.message}`);
    }
  }
}

module.exports = EntryPoint;
<commit_msg>rename funnel:beforeRequestExecution to request:beforeExecution and use modified request return by the pipe<commit_after>/*
 * Kuzzle, a backend software, self-hostable and ready to use
 * to power modern apps
 *
 * Copyright 2015-2020 Kuzzle
 * mailto: support AT kuzzle.io
 * website: http://kuzzle.io
 *
 * 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
 *
 * https://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.
 */

'use strict';

const fs = require('fs');
const path = require('path');

const Bluebird = require('bluebird');

const { RequestContext } = require('../../api/request');
const Context = require('./context');
const debug = require('../../util/debug')('kuzzle:network:embedded');
const MqttProtocol = require('./protocols/mqttProtocol');
const InternalProtocol = require('./protocols/internalProtocol');
const HttpWsProtocol = require('./protocols/httpwsProtocol');
const Manifest = require('./protocolManifest');
const removeErrorStack = require('./removeErrorStack');
const kerror = require('../../kerror');
const { AccessLogger } = require('./accessLogger');

const networkError = kerror.wrap('network', 'entrypoint');

const DEFAULT_PROTOCOLS = [
  HttpWsProtocol,
  MqttProtocol,
  InternalProtocol,
];

class EntryPoint {
  constructor () {
    this.config = global.kuzzle.config.server;

    this.protocols = new Map();

    this._clients = new Map();

    this.accessLogger = new AccessLogger();

    this.isShuttingDown = false;
  }

  dispatch (event, data) {
    switch (event) {
      case 'notify':
        this._notify(data);
        return;
      case 'broadcast':
        this._broadcast(data);
        return;
      case 'shutdown':
        this.isShuttingDown = true;
        return ;
      default:
        throw networkError.get('unexpected_event', event);
    }
  }

  /**
   * Initializes the InternalProtocol first to allow subscriptions
   * in plugins init() method.
   *
   * @returns {Promise}
   */
  async init () {
    for (const ProtocolClass of DEFAULT_PROTOCOLS) {
      const protocol = new ProtocolClass();

      this.protocols.set(protocol.name, protocol);
    }

    return this.protocols.get('internal').init(this);
  }

  /**
   * Starts the network protocols.
   * Every protocol is listening for request after this call
   *
   * @returns {Promise}
   */
  async startListening () {
    // We need to verify the port ourselves, to make sure Node.js won't open
    // a named pipe if the provided port number is a string
    if (!Number.isInteger(this.config.port)) {
      throw networkError.get('invalid_port', this.config.port);
    }

    await this.accessLogger.init();

    const initPromises = [];

    for (const protocol of this.protocols.values()) {
      // InternalProtocol is already initialized
      if (protocol.initCalled) {
        continue;
      }

      initPromises.push(protocol.init(this)
        .then(enabled => {
          if (! enabled) {
            this.protocols.delete(protocol.name);
          }
        })
      );
    }

    await Bluebird.all(initPromises);

    await this.loadMoreProtocols();
  }

  /**
   * On client subscribing to a channel, dispatch the information
   * to the protocol.
   *
   * @param {string} channel
   * @param {string} connectionId
   */
  joinChannel (channel, connectionId) {
    debug('[server] client "%s" joining channel "%s"', connectionId, channel);

    const client = this._clients.get(connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).joinChannel(channel, connectionId);
    }
    catch (e) {
      global.kuzzle.log.error(`[join] protocol ${client && client.protocol} failed: ${e.message}`);
    }
  }

  leaveChannel (channel, connectionId) {
    debug(
      '[server] connection "%s" leaving channel "%s"',
      connectionId,
      channel);

    const client = this._clients.get(connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).leaveChannel(channel, connectionId);
    }
    catch (e) {
      global.kuzzle.log.error(`[leave channel] protocol ${client && client.protocol} failed: ${e.message}`);
    }
  }

  /**
   * Loads installed protocols in memory
   */
  async loadMoreProtocols () {
    const dir = path.join(__dirname, '../../../protocols/enabled');
    let dirs;

    try {
      dirs = fs.readdirSync(dir);
    }
    catch (e) {
      // ignore if there is no protocols directory
      return;
    }

    dirs = dirs
      .map(d => path.join(dir, d))
      .filter(d => fs.statSync(d).isDirectory());

    await Bluebird.map(dirs, protoDir => {
      const protocol = new (require(protoDir))();
      const manifest = new Manifest(protoDir, protocol);

      manifest.load();

      const initTimeout = global.kuzzle.config.services.common.defaultInitTimeout;

      return Bluebird.resolve()
        .then(() => protocol.init(this, new Context()))
        .catch(error => {
          global.kuzzle.log.error(`Error during "${manifest.name}" protocol init:`);
          throw error;
        })
        .timeout(initTimeout, `Protocol "${manifest.name}" initialization timed out after ${initTimeout}ms. Try to increase the configuration "services.common.defaultInitTimeout".`)
        .then(() => {
          if (this.protocols.has(manifest.name)) {
            throw kerror.get('protocol', 'runtime', 'already_exists', manifest.name);
          }

          this.protocols.set(manifest.name, protocol);
        });
    });
  }

  /**
   * @param {ClientConnection} connection
   * @param {Request} request
   * @param {object} extra
   */
  logAccess (connection, request, extra = null) {
    this.accessLogger.log(connection, request, extra);
  }

  /*
  -----------------------------------------------------------------------
  methods exposed to protocols
  -----------------------------------------------------------------------
  */

  /**
   * @param {ClientConnection} connection
   * @param {Request} request
   * @param cb
   */
  execute (connection, request, cb) {
    if (this.isShuttingDown) {
      debug('Shutting down. Dropping request: %a', request);
      this._isShuttingDownError(connection, request, cb);
      return;
    }

    debug('Funneling request: %a', request);

    global.kuzzle.pipe('request:beforeExecution', request)
      .then((modifiedRequest) => {
        global.kuzzle.funnel.execute(modifiedRequest, (error, result) => {
          const _res = result || modifiedRequest;

          if (error && !_res.error) {
            _res.setError(error);
          }

          this.logAccess(connection, _res);

          const response = _res.response.toJSON();

          cb(removeErrorStack(response));
        });
      }).catch((err) => {
        request.setError(err);

        this.logAccess(connection, request);

        const response = request.response.toJSON();

        cb(removeErrorStack(response));
      });
  }

  /**
   *
   * @param {ClientConnection} connection
   */
  newConnection (connection) {
    this._clients.set(connection.id, connection);

    global.kuzzle.emit('connection:new', connection);
    global.kuzzle.router.newConnection(new RequestContext({ connection }));
    debug(
      'New connection created: %s (protocol: %s)',
      connection.id,
      connection.protocol);
  }

  /**
   * @param {string} connectionId
   */
  removeConnection (connectionId) {
    const connection = this._clients.get(connectionId);

    if (connection) {
      global.kuzzle.emit('connection:remove', connection);

      global.kuzzle.router.removeConnection(new RequestContext({ connection }));

      this._clients.delete(connectionId);

      debug(
        'Removed connection: %s (protocol: %s)',
        connection.id,
        connection.protocol);
    }
  }

  // --------------------------------------------------------------------

  _broadcast (data) {
    const sanitized = removeErrorStack(data);

    debug('[server] broadcasting data through all protocols: %a', sanitized);

    for (const [name, protocol] of this.protocols.entries()) {
      try {
        protocol.broadcast(sanitized);
      }
      catch (e) {
        global.kuzzle.log.error(`[broadcast] protocol ${name} failed: ${e.message}\n${e.stack}`);
      }
    }
  }

  _isShuttingDownError (connection, request, cb) {
    request.setError(networkError.get('shutting_down'));
    this.logAccess(connection, request);

    cb(removeErrorStack(request.response.toJSON()));
  }

  _notify (data) {
    debug(
      '[server] sending notification to client with connection id "%s": %a',
      data.connectionId,
      data);

    const client = this._clients.get(data.connectionId);

    if (!client || !client.protocol) {
      return;
    }

    try {
      this.protocols.get(client.protocol).notify(removeErrorStack(data));
    }
    catch (e) {
      global.kuzzle.log.error(`[notify] protocol ${client.protocol} failed: ${e.message}`);
    }
  }
}

module.exports = EntryPoint;
<|endoftext|>


<commit_before>"use strict";

/**
 * @author EmmanuelOlaojo
 * @since 8/9/16
 */
var modelCache = {};
var Promise = require("bluebird");

var constants = require("../constants");
var mongoose;

module.exports = function(_mongoose) {
  mongoose = _mongoose;
  var Schema = mongoose.Schema;

  /**
   * gets a collection as a mongoose model.
   *
   * @param name name of the collection
   * @param schema schema for the model
   */
  function getCollection(name, schema){
    if (schema) return mongoose.model(name, schema);

    try {
      return mongoose.model(name);
    } catch (err){
      initModel(name, schema);
      return mongoose.model(name);
    }
  }

  /**
   * Adds a model to the model cache
   *
   * @param name name of model
   * @param schema schema for the model
   */
  function setModel(name, schema) {
    modelCache[name] = getCollection(name, schema);
  }

  /**
   * Gets a mongoose model. Creates one if it
   * doesn't exist already.
   *
   * @param name name of the model to retrieve
   * @param schema schema for the model
   *
   * @returns a mongoose model
   */
  function getModel(name, schema) {
    if (!modelCache[name]) {
      setModel(name, schema);
    }

    return modelCache[name];
  }

  /**
   * Initializes a mongoose model with name: modelName.
   * If a schema is provided, it will be used to construct the model
   * else, the model will be initialized with a default, unrestricted
   * schema.
   *
   * @param modelName The intended name of the model
   * @param schema The schema associated with this model
   */
  function initModel(modelName, schema) {
    if (modelCache[modelName]) throw new Error("The schema for this model has already been set");
    if (schema && typeof schema !== "object") throw new Error("Invalid Schema");

    var DEFAULT_SCHEMA = new Schema({}, {strict: false});

    setModel(modelName, schema ? new Schema(schema, {strict: true}) : DEFAULT_SCHEMA);
  }

  /**
   * Drops a MongoDB collection. For testing.
   *
   * @param collection the name of the collection to be dropped
   */
  function dropCollection(collection) {
    return new Promise(function(resolve, reject) {
      mongoose.connection.db.dropCollection(collection, function(err) {
        if(err) reject(err);
        else resolve();
      });
    });
  }

  /**
   * Removes a file from the db
   *
   * @param id file id or options object
   * @param gfs GridFS
   */
  function removeFile(id, gfs) {
    var options = {_id: id};

    if (id.constructor && id.constructor === Object) {
      options = id;
    }

    return new Promise(function (resolve, reject) {
      gfs.remove(options, function (err, result) {
        if (err) return reject(err);

        resolve(result);
      });
    });
  }

  /**
   * Checks if a file exists in the db with the
   * specified file name
   *
   * @param id MongoDB ObjectId
   * @param gfs GridFS
   */
  function fileExists(id, gfs) {
    return new Promise(function (resolve, reject) {
      gfs.exist({_id: id}, function (err, exists) {
        if (err) return reject(err);

        resolve(exists);
      });
    });
  }

  /**
   * Chains together the deletion of shadow files
   * from file remove steps.
   *
   * @param task the task to check for shadow files
   * @param gfs GridFS
   *
   * @returns {Promise|*}
   */
  function makeRemoveChain(task, gfs) {
    var removeChain = Promise.resolve();

    task.steps.forEach(function (step) {
      if (step.type !== constants.FILE_REMOVE) return;

      var shadowId = step.dataStore[0].shadow;

      removeChain = removeChain.then(function () {
        return fileExists(shadowId, gfs)
          .then(function (exists) {
            if (!exists) return Promise.resolve();

            return removeFile(shadowId, gfs);
          });
      });
    });

    return removeChain;
  }

    /**
     * generates a MongoDB ObjectId
     */
    function generateId(id) {
        return new mongoose.Types.ObjectId(id);
    }

    /**
     * Gets the collection for a step
     *
     * @param db native db
     * @param step the step in question
     *
     * @returns native collection
     */
    function getCollectionForStep(db, step){
        return step.useMongoose
            ? mongoose.model(step.name).collection
            : db.collection(step.name)
    }

    /**
     * This function stores data that's about to be
     * changed by a step, for rollback purposes
     *
     * @param db native db
     * @param step the step
     * @param condition literal obj rep of the step's condition
     *
     * @returns {Promise|*}
     */
    function storeOldData(db, step, condition){
        var Collection = getCollectionForStep(db, step);
        var options = step.options
            ? utils.xcode(step.options)
            : step.type === constants.REMOVE ? {multi: true} : null;
        var query = Collection.find(condition);
        var searchQuery = options && options.multi === true
            ? query
            : query.limit(1);

        return searchQuery.toArray().then(function(result){
            step.dataStore = result;
        });
    }
  return {
    setModel: setModel
    , getModel: getModel
    , initModel: initModel
    , modelCache: modelCache
    , dropCollection: dropCollection
    , removeFile: removeFile
    , fileExists: fileExists
    , makeRemoveChain: makeRemoveChain
    , generateId: generateId
    , getCollection: getCollection
    , getCollectionForStep: getCollectionForStep
    , storeOldData: storeOldData
  };
};
<commit_msg>Initialized utils for utils not found error<commit_after>"use strict";

/**
 * @author EmmanuelOlaojo
 * @since 8/9/16
 */
var modelCache = {};
var Promise = require("bluebird");

var constants = require("../constants");
var utils = require("./gen.utils");
var mongoose;

module.exports = function(_mongoose) {
  mongoose = _mongoose;
  var Schema = mongoose.Schema;

  /**
   * gets a collection as a mongoose model.
   *
   * @param name name of the collection
   * @param schema schema for the model
   */
  function getCollection(name, schema){
    if (schema) return mongoose.model(name, schema);

    try {
      return mongoose.model(name);
    } catch (err){
      initModel(name, schema);
      return mongoose.model(name);
    }
  }

  /**
   * Adds a model to the model cache
   *
   * @param name name of model
   * @param schema schema for the model
   */
  function setModel(name, schema) {
    modelCache[name] = getCollection(name, schema);
  }

  /**
   * Gets a mongoose model. Creates one if it
   * doesn't exist already.
   *
   * @param name name of the model to retrieve
   * @param schema schema for the model
   *
   * @returns a mongoose model
   */
  function getModel(name, schema) {
    if (!modelCache[name]) {
      setModel(name, schema);
    }

    return modelCache[name];
  }

  /**
   * Initializes a mongoose model with name: modelName.
   * If a schema is provided, it will be used to construct the model
   * else, the model will be initialized with a default, unrestricted
   * schema.
   *
   * @param modelName The intended name of the model
   * @param schema The schema associated with this model
   */
  function initModel(modelName, schema) {
    if (modelCache[modelName]) throw new Error("The schema for this model has already been set");
    if (schema && typeof schema !== "object") throw new Error("Invalid Schema");

    var DEFAULT_SCHEMA = new Schema({}, {strict: false});

    setModel(modelName, schema ? new Schema(schema, {strict: true}) : DEFAULT_SCHEMA);
  }

  /**
   * Drops a MongoDB collection. For testing.
   *
   * @param collection the name of the collection to be dropped
   */
  function dropCollection(collection) {
    return new Promise(function(resolve, reject) {
      mongoose.connection.db.dropCollection(collection, function(err) {
        if(err) reject(err);
        else resolve();
      });
    });
  }

  /**
   * Removes a file from the db
   *
   * @param id file id or options object
   * @param gfs GridFS
   */
  function removeFile(id, gfs) {
    var options = {_id: id};

    if (id.constructor && id.constructor === Object) {
      options = id;
    }

    return new Promise(function (resolve, reject) {
      gfs.remove(options, function (err, result) {
        if (err) return reject(err);

        resolve(result);
      });
    });
  }

  /**
   * Checks if a file exists in the db with the
   * specified file name
   *
   * @param id MongoDB ObjectId
   * @param gfs GridFS
   */
  function fileExists(id, gfs) {
    return new Promise(function (resolve, reject) {
      gfs.exist({_id: id}, function (err, exists) {
        if (err) return reject(err);

        resolve(exists);
      });
    });
  }

  /**
   * Chains together the deletion of shadow files
   * from file remove steps.
   *
   * @param task the task to check for shadow files
   * @param gfs GridFS
   *
   * @returns {Promise|*}
   */
  function makeRemoveChain(task, gfs) {
    var removeChain = Promise.resolve();

    task.steps.forEach(function (step) {
      if (step.type !== constants.FILE_REMOVE) return;

      var shadowId = step.dataStore[0].shadow;

      removeChain = removeChain.then(function () {
        return fileExists(shadowId, gfs)
          .then(function (exists) {
            if (!exists) return Promise.resolve();

            return removeFile(shadowId, gfs);
          });
      });
    });

    return removeChain;
  }

    /**
     * generates a MongoDB ObjectId
     */
    function generateId(id) {
        return new mongoose.Types.ObjectId(id);
    }

    /**
     * Gets the collection for a step
     *
     * @param db native db
     * @param step the step in question
     *
     * @returns native collection
     */
    function getCollectionForStep(db, step){
        return step.useMongoose
            ? mongoose.model(step.name).collection
            : db.collection(step.name)
    }

    /**
     * This function stores data that's about to be
     * changed by a step, for rollback purposes
     *
     * @param db native db
     * @param step the step
     * @param condition literal obj rep of the step's condition
     *
     * @returns {Promise|*}
     */
    function storeOldData(db, step, condition){
        var Collection = getCollectionForStep(db, step);
        var options = step.options
            ? utils.xcode(step.options)
            : step.type === constants.REMOVE ? {multi: true} : null;
        var query = Collection.find(condition);
        var searchQuery = options && options.multi === true
            ? query
            : query.limit(1);

        return searchQuery.toArray().then(function(result){
            step.dataStore = result;
        });
    }
  return {
    setModel: setModel
    , getModel: getModel
    , initModel: initModel
    , modelCache: modelCache
    , dropCollection: dropCollection
    , removeFile: removeFile
    , fileExists: fileExists
    , makeRemoveChain: makeRemoveChain
    , generateId: generateId
    , getCollection: getCollection
    , getCollectionForStep: getCollectionForStep
    , storeOldData: storeOldData
  };
};
<|endoftext|>


<commit_before>var md5Hex = require('md5-hex');

// Get gravatar url
function gravatarUrl(email) {
    return 'http://www.gravatar.com/avatar/'+md5Hex(email)+'?s=200&d='+encodeURIComponent('https://www.gitbook.com/assets/images/avatars/user.png');
}

module.exports = {
    url: gravatarUrl
};
<commit_msg>Use HTTPS for gravatar (#24)<commit_after>var md5Hex = require('md5-hex');

// Get gravatar url
function gravatarUrl(email) {
    return 'https://www.gravatar.com/avatar/'+md5Hex(email)+'?s=200&d='+encodeURIComponent('https://www.gitbook.com/assets/images/avatars/user.png');
}

module.exports = {
    url: gravatarUrl
};
<|endoftext|>


<commit_before>var aug = require('aug');
var fs = require('fs');
var hl = require('highlight.js');
var marked = require('marked');

module.exports = function(text, highlight, callback) {

  marked.setOptions({
    // callback for code highlighter
    gfm: true,
    pedantic: false,
    sanitize: false,
    highlight: function(code, lang) {

      var out;
      if (!highlight) {
        out = code;
      } else if (lang) {
        out = hl.highlight(lang, code).value;
      } else {
        out = hl.highlightAuto(code).value;
      }
      return out;
    }
  });
  var result = marked(text);
  callback(null, result);
};

<commit_msg>fix for language == html<commit_after>var aug = require('aug');
var fs = require('fs');
var hl = require('highlight.js');
var marked = require('marked');

module.exports = function(text, highlight, callback) {

  marked.setOptions({
    // callback for code highlighter
    gfm: true,
    pedantic: false,
    sanitize: false,
    highlight: function(code, lang) {

      if (lang == 'html') {
        lang = 'xml';
      }
      var out;
      if (!highlight) {
        out = code;
      } else if (lang) {
        out = hl.highlight(lang, code).value;
      } else {
        out = hl.highlightAuto(code).value;
      }
      return out;
    }
  });
  var result = marked(text);
  callback(null, result);
};

<|endoftext|>


<commit_before>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")
  , Buffer = require("buffer").Buffer
  , fs = require("fs")
  , path = require("path")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try { reg() }
  catch (ex) { return cb(ex) }

  var fullData =
    { _id : data.name
    , name : data.name
    , description : data.description
    , "dist-tags" : {}
    , versions : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  var attURI = encodeURIComponent(data.name)
             + "/-/"
             + encodeURIComponent(data.name)
             + "-"
             + encodeURIComponent(data.version)
             + ".tgz"
  data.dist = { "tarball" : url.resolve(npm.config.get("registry"), attURI) }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(encodeURIComponent(data.name), fullData, function (er) {
    // get the rev and then upload the attachment
    if (er) log(er, "PUT response")
    var sendVersionAgain = !!er
    GET(encodeURIComponent(data.name), function (er, d) {
      if (er) return cb(er)
      var rev = d && d._rev
        , tarball = path.join(npm.cache, data.name, data.version, "package.tgz")
        , dataURI = encodeURIComponent(data.name)+"/"+encodeURIComponent(data.version)
      attURI += "/" + rev
      upload(attURI, tarball, function (er) {
        if (!sendVersionAgain) return log.er(cb, "Couldn't send tarball")(er)
        PUT(dataURI, data, log.er(cb, "Error sending version data"))
      })
    })
  })
}
function request (method, where, what, cb) {
  if (typeof what === "function" && !cb) {
    cb = what
    what = null
  }
  try { reg() }
  catch (ex) { return cb(ex) }

  var authRequired = what && !where.match(/^\/?adduser\/org\.couchdb\.user:/)
  where = url.resolve(npm.config.get("registry"), where)
  var u = url.parse(where)
    , https = u.protocol === "https:"
    , auth = authRequired && npm.config.get("auth")

  if (authRequired && !auth) {
    return cb(new Error(
      "Cannot insert data into the registry without authorization and https\n"
      + "See: npm-adduser(1)"))
  }
  if (auth && !https) {
    log("Sending authorization over insecure channel.", "WARNING")
  }
  var headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (auth) headers.authorization = "Basic " + auth
  if (what) {
    if (what instanceof File) {
      what = what.data
      headers["content-type"] = "application/octet-stream"
    } else {
      what = JSON.stringify(what)
      headers["content-type"] = "application/json"
    }
    headers["content-length"] = what.length
  }

  var client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request(method, u.pathname, headers)
  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      var parsed
      try {
        parsed = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, null, data, response)
      }
      if (parsed && parsed.error) return cb(new Error(
        parsed.error + (" "+parsed.reason || "")))
      cb(null, parsed, data, response)
    })
  })
  if (what) request.write(what, "ascii")
  request.end()
}

function GET (where, cb) { request("GET", where, cb) }
function PUT (where, what, cb) { request("PUT", where, what, cb) }

function upload (where, filename, cb) {
  new File(filename, function (er, f) {
    if (er) log.er(cb, "Couldn't open "+filename)(er)
    PUT(where, f, cb)
  })
}
function File (name, cb) {
  var f = this
  f.name = name
  if (f.loaded) return cb(null, f)
  fs.stat(f.name, function (er, stat) {
    if (er) return log.er(cb, "doesn't exist "+f.name)(er)
    fs.readFile(f.name, function (er, data) {
      if (er) return log.er(cb, "problem reading "+f.name)(er)
      f.data = data
      cb(null, f)
    })
  })
}

function reg () {
  var r = npm.config.get("registry")
  if (!r) throw new Error(
    "Must define registry URL before accessing registry.")
  if (r.substr(-1) !== "/") {
    r += "/"
  }
  npm.config.set("registry", r)
  return r
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
    , userobj =
      { _id : 'org.couchdb.user:'+username
      , name : username
      , type : "user"
      , roles : []
      , salt : salt
      , password_sha : sha.hex_sha1(password + salt)
      , email : email
      }
  PUT
    ( '/adduser/org.couchdb.user:'+encodeURIComponent(username)
    , userobj
    , function (error, data, json, response) {
        // if the error is a 409, then update the rev.
        if (error || response && response.statusCode !== 201) {
          log(response && response.statusCode, "response")
          log(error, "error")
          return callback(new Error( (response && response.statusCode) + " "+
            "Could not create user "+error+'\n'+JSON.stringify(data)))
        }
        callback()
      }
    )
}
<commit_msg>Don't log the expected error object, since it makes people think it failed.<commit_after>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")
  , Buffer = require("buffer").Buffer
  , fs = require("fs")
  , path = require("path")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try { reg() }
  catch (ex) { return cb(ex) }

  var fullData =
    { _id : data.name
    , name : data.name
    , description : data.description
    , "dist-tags" : {}
    , versions : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  var attURI = encodeURIComponent(data.name)
             + "/-/"
             + encodeURIComponent(data.name)
             + "-"
             + encodeURIComponent(data.version)
             + ".tgz"
  data.dist = { "tarball" : url.resolve(npm.config.get("registry"), attURI) }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(encodeURIComponent(data.name), fullData, function (er, data, json, response) {
    // get the rev and then upload the attachment
    // a 409 is expected here, if this is a new version of an existing package.
    if (error && !(response && response.statusCode !== 409)) {
      return log.er(cb, "Failed PUT response")(er)
    }
    var sendVersionAgain = !!er
    GET(encodeURIComponent(data.name), function (er, d) {
      if (er) return cb(er)
      var rev = d && d._rev
        , tarball = path.join(npm.cache, data.name, data.version, "package.tgz")
        , dataURI = encodeURIComponent(data.name)+"/"+encodeURIComponent(data.version)
      attURI += "/" + rev
      upload(attURI, tarball, function (er) {
        if (!sendVersionAgain) return log.er(cb, "Couldn't send tarball")(er)
        PUT(dataURI, data, log.er(cb, "Error sending version data"))
      })
    })
  })
}
function request (method, where, what, cb) {
  if (typeof what === "function" && !cb) {
    cb = what
    what = null
  }
  try { reg() }
  catch (ex) { return cb(ex) }

  var authRequired = what && !where.match(/^\/?adduser\/org\.couchdb\.user:/)
  where = url.resolve(npm.config.get("registry"), where)
  var u = url.parse(where)
    , https = u.protocol === "https:"
    , auth = authRequired && npm.config.get("auth")

  if (authRequired && !auth) {
    return cb(new Error(
      "Cannot insert data into the registry without authorization and https\n"
      + "See: npm-adduser(1)"))
  }
  if (auth && !https) {
    log("Sending authorization over insecure channel.", "WARNING")
  }
  var headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (auth) headers.authorization = "Basic " + auth
  if (what) {
    if (what instanceof File) {
      what = what.data
      headers["content-type"] = "application/octet-stream"
    } else {
      what = JSON.stringify(what)
      headers["content-type"] = "application/json"
    }
    headers["content-length"] = what.length
  }

  var client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request(method, u.pathname, headers)
  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      var parsed
      try {
        parsed = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, null, data, response)
      }
      if (parsed && parsed.error) return cb(new Error(
        parsed.error + (" "+parsed.reason || "")))
      cb(null, parsed, data, response)
    })
  })
  if (what) request.write(what, "ascii")
  request.end()
}

function GET (where, cb) { request("GET", where, cb) }
function PUT (where, what, cb) { request("PUT", where, what, cb) }

function upload (where, filename, cb) {
  new File(filename, function (er, f) {
    if (er) log.er(cb, "Couldn't open "+filename)(er)
    PUT(where, f, cb)
  })
}
function File (name, cb) {
  var f = this
  f.name = name
  if (f.loaded) return cb(null, f)
  fs.stat(f.name, function (er, stat) {
    if (er) return log.er(cb, "doesn't exist "+f.name)(er)
    fs.readFile(f.name, function (er, data) {
      if (er) return log.er(cb, "problem reading "+f.name)(er)
      f.data = data
      cb(null, f)
    })
  })
}

function reg () {
  var r = npm.config.get("registry")
  if (!r) throw new Error(
    "Must define registry URL before accessing registry.")
  if (r.substr(-1) !== "/") {
    r += "/"
  }
  npm.config.set("registry", r)
  return r
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
    , userobj =
      { _id : 'org.couchdb.user:'+username
      , name : username
      , type : "user"
      , roles : []
      , salt : salt
      , password_sha : sha.hex_sha1(password + salt)
      , email : email
      }
  PUT
    ( '/adduser/org.couchdb.user:'+encodeURIComponent(username)
    , userobj
    , function (error, data, json, response) {
        // if the error is a 409, then update the rev.
        if (error || response && response.statusCode !== 201) {
          log(response && response.statusCode, "response")
          log(error, "error")
          return callback(new Error( (response && response.statusCode) + " "+
            "Could not create user "+error+'\n'+JSON.stringify(data)))
        }
        callback()
      }
    )
}
<|endoftext|>


<commit_before>/*jshint esversion:6, node:true*/
'use strict';

class JSONParser {
    constructor(manager) {
        manager.parser('json', this.parse.bind(this));
    }

    /**
     * Parse JSON into an array of results. Assumes top-level is array, unless
     *  opts.key is provided to pick a top-level key from parsed object as results.
     * @param {string} contents
     * @param {object} options
     */
    parse(contents, opts) {
        let results = JSON.parse(contents);
        if (opts.key) results = results[opts.key];
        return results;
    }
}

module.exports = JSONParser;
<commit_msg>data-manager: fix jsonparser<commit_after>/*jshint esversion:6, node:true*/
'use strict';

class JSONParser {
    constructor(manager) {
        manager.parser('json', this.parse.bind(this));
    }

    /**
     * Parse JSON into an array of results. Assumes top-level is array, unless
     *  opts.key is provided to pick a top-level key from parsed object as results.
     * @param {string} contents
     * @param {object} options
     */
    parse(contents, opts) {
        if(typeof contents === 'object') return contents;
        let results = JSON.parse(contents);
        if (opts.key) results = results[opts.key];
        return results;
    }
}

module.exports = JSONParser;
<|endoftext|>


<commit_before>
if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}

define(
  [
    'require',
    'underscore',
    './wand-base-class'
  ],
  function (
    require,
    _,
    BaseClass
  ) {

    return BaseClass.extend(
      {
        constructor: function()
        {
          console.log('Templater constructor');
        },
        doSomething: function()
        {
          console.log('Templater.doSomething');
        }
      }
    );

});<commit_msg>Templater working as instantiatable prototype.<commit_after>
if (typeof define !== 'function') {
  var define = require('amdefine')(module);
}

define(
  [
    'require',
    'underscore',
    'handlebars',
    './wand-base-class'
  ],
  function (
    require,
    _,
    Handlebars,
    BaseClass
  ) {

    return BaseClass.extend(
      {
        constructor: function()
        {
          this.initialize.apply(this, arguments);
        },

        initialize: function(options)
        {
          this.rawTemplates = options.rawTemplates ? options.rawTemplates : {};
          this.compiledTemplates = options.compiledTemplates ? options.compiledTemplates : {};

          this.createHandlebarsHelper();
        },

        compile: function(id, data)
        {
          return this.getCompiledTemplate(id)(data);
        },

        addTemplates: function(templates)
        {
          _.each(
            templates,
            function(template)
            {
              this.rawTemplates[template.id] = template.value;
            },
            this
          );
        },

        getCompiledTemplate: function(id)
        {
          var compiledTemplate = this.compiledTemplates[id];
          if(!compiledTemplate)
          {
            compiledTemplate = Handlebars.compile(this.getRawTemplate(id));
            this.compiledTemplates[id] = compiledTemplate;
          }

          return compiledTemplate;
        },

        getRawTemplate: function(id)
        {
          return this.rawTemplates[id];
        },

        createHandlebarsHelper: function()
        {
          var self = this;

          Handlebars.registerHelper(
            "template",
            function(templateName, data)
            {
              return self.compile(templateName, data);
            }
          );
        }

      }
    );

});<|endoftext|>


<commit_before>/*
 * common.js: Internal helper and utility functions for winston
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENCE
 *
 */

var util = require('util'),
    crypto = require('crypto'),
    loggly = require('loggly'),
    config = require('./config');

//
// ### function setLevels (target, past, current)
// #### @target {Object} Object on which to set levels.
// #### @past {Object} Previous levels set on target.
// #### @current {Object} Current levels to set on target.
// Create functions on the target objects for each level
// in current.levels. If past is defined, remove functions
// for each of those levels.
//
exports.setLevels = function (target, past, current, isDefault) {
  if (past) {
    Object.keys(past).forEach(function (level) {
      delete target[level];
    });
  }

  target.levels = current || config.npm.levels;
  if (target.padLevels) {
    target.levelLength = exports.longestElement(Object.keys(target.levels));
  }

  //
  //  Define prototype methods for each log level
  //  e.g. target.log('info', msg) <=> target.info(msg)
  //
  Object.keys(target.levels).forEach(function (level) {
    target[level] = function (msg) {
      var args     = Array.prototype.slice.call(arguments),
          callback = typeof args[args.length - 1] === 'function' ? args.pop() : null,
          meta     = args.length === 2 ? args.pop() : null;

      return target.log(level, msg, meta, callback);
    };
  });

  return target;
};

//
// ### function longestElement
// #### @xs {Array} Array to calculate against
// Returns the longest element in the `xs` array.
//
exports.longestElement = function (xs) {
  return Math.max.apply(
    null,
    xs.map(function (x) { return x.length })
  );
};

//
// ### function clone (obj)
// #### @obj {Object} Object to clone.
// Helper method for deep cloning pure JSON objects
// i.e. JSON objects that are either literals or objects (no Arrays, etc)
//
exports.clone = function (obj) {
  var copy = {};
  for (var i in obj) {
    if (Array.isArray(obj[i])) {
      copy[i] = obj[i].slice(0);
    }
    else {
      copy[i] = obj[i] instanceof Object ? exports.clone(obj[i]) : obj[i];
    }
  }

  return copy;
};

//
// ### function log (options)
// #### @options {Object} All information about the log serialization.
// Generic logging function for returning timestamped strings
// with the following options:
//
//    {
//      level:     'level to add to serialized message',
//      message:   'message to serialize',
//      meta:      'additional logging metadata to serialize',
//      colorize:  false, // Colorizes output (only if `.json` is false)
//      timestamp: true   // Adds a timestamp to the serialized message
//    }
//
exports.log = function (options) {
  var timestampFn = typeof options.timestamp === 'function' ? options.timestamp : exports.timestamp,
      timestamp   = options.timestamp ? timestampFn() : null,
      meta        = options.meta ? exports.clone(options.meta) : null,
      output;

  if (options.json) {
    output         = meta || {};
    output.level   = options.level;
    output.message = options.message;

    if (timestamp) {
      output.timestamp = timestamp;
    }

    return typeof options.stringify === 'function'
      ? options.stringify(output)
      : JSON.stringify(output);
  }

  output = timestamp ? timestamp + ' - ' : '';
  output += options.colorize ? config.colorize(options.level) : options.level;
  output += (': ' + options.message);

  if (meta && typeof meta === 'object' && Object.keys(meta).length > 0) {
    output += ' ' + loggly.serialize(meta);
  }

  return output;
};

exports.capitalize = function (str) {
  return str && str[0].toUpperCase() + str.slice(1);
};

//
// ### function hash (str)
// #### @str {string} String to hash.
// Utility function for creating unique ids
// e.g. Profiling incoming HTTP requests on the same tick
//
exports.hash = function (str) {
  return crypto.createHash('sha1').update(str).digest('hex');
};

//
// ## Borrowed from node.js core
// I wanted a universal lowercase header message, as opposed to the `DEBUG`
// (i.e. all uppercase header) used only in `util.debug()`
//
var months = ['Jan', 'Feb', 'Mar', 'Apr',
              'May', 'Jun', 'Jul', 'Aug',
              'Sep', 'Oct', 'Nov', 'Dec'];

//
// ### function pad (n)
// Returns a padded string if `n < 10`.
//
exports.pad = function (n) {
  return n < 10 ? '0' + n.toString(10) : n.toString(10);
};

//
// ### function timestamp ()
// Returns a timestamp string for the current time.
//
exports.timestamp = function () {
  var d = new Date();
  var time = [
    exports.pad(d.getHours()),
    exports.pad(d.getMinutes()),
    exports.pad(d.getSeconds())
  ].join(':');

  return [d.getDate(), months[d.getMonth()], time].join(' ');
};<commit_msg>[optimize] Increase load-time by 25% by duplicating some hoisted code<commit_after>/*
 * common.js: Internal helper and utility functions for winston
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENCE
 *
 */

var util = require('util'),
    crypto = require('crypto'),
    config = require('./config');

//
// ### function setLevels (target, past, current)
// #### @target {Object} Object on which to set levels.
// #### @past {Object} Previous levels set on target.
// #### @current {Object} Current levels to set on target.
// Create functions on the target objects for each level
// in current.levels. If past is defined, remove functions
// for each of those levels.
//
exports.setLevels = function (target, past, current, isDefault) {
  if (past) {
    Object.keys(past).forEach(function (level) {
      delete target[level];
    });
  }

  target.levels = current || config.npm.levels;
  if (target.padLevels) {
    target.levelLength = exports.longestElement(Object.keys(target.levels));
  }

  //
  //  Define prototype methods for each log level
  //  e.g. target.log('info', msg) <=> target.info(msg)
  //
  Object.keys(target.levels).forEach(function (level) {
    target[level] = function (msg) {
      var args     = Array.prototype.slice.call(arguments),
          callback = typeof args[args.length - 1] === 'function' ? args.pop() : null,
          meta     = args.length === 2 ? args.pop() : null;

      return target.log(level, msg, meta, callback);
    };
  });

  return target;
};

//
// ### function longestElement
// #### @xs {Array} Array to calculate against
// Returns the longest element in the `xs` array.
//
exports.longestElement = function (xs) {
  return Math.max.apply(
    null,
    xs.map(function (x) { return x.length })
  );
};

//
// ### function clone (obj)
// #### @obj {Object} Object to clone.
// Helper method for deep cloning pure JSON objects
// i.e. JSON objects that are either literals or objects (no Arrays, etc)
//
exports.clone = function (obj) {
  var copy = {};
  for (var i in obj) {
    if (Array.isArray(obj[i])) {
      copy[i] = obj[i].slice(0);
    }
    else {
      copy[i] = obj[i] instanceof Object ? exports.clone(obj[i]) : obj[i];
    }
  }

  return copy;
};

//
// ### function log (options)
// #### @options {Object} All information about the log serialization.
// Generic logging function for returning timestamped strings
// with the following options:
//
//    {
//      level:     'level to add to serialized message',
//      message:   'message to serialize',
//      meta:      'additional logging metadata to serialize',
//      colorize:  false, // Colorizes output (only if `.json` is false)
//      timestamp: true   // Adds a timestamp to the serialized message
//    }
//
exports.log = function (options) {
  var timestampFn = typeof options.timestamp === 'function' ? options.timestamp : exports.timestamp,
      timestamp   = options.timestamp ? timestampFn() : null,
      meta        = options.meta ? exports.clone(options.meta) : null,
      output;

  if (options.json) {
    output         = meta || {};
    output.level   = options.level;
    output.message = options.message;

    if (timestamp) {
      output.timestamp = timestamp;
    }

    return typeof options.stringify === 'function'
      ? options.stringify(output)
      : JSON.stringify(output);
  }

  output = timestamp ? timestamp + ' - ' : '';
  output += options.colorize ? config.colorize(options.level) : options.level;
  output += (': ' + options.message);

  if (meta && typeof meta === 'object' && Object.keys(meta).length > 0) {
    output += ' ' + exports.serialize(meta);
  }

  return output;
};

exports.capitalize = function (str) {
  return str && str[0].toUpperCase() + str.slice(1);
};

//
// ### function hash (str)
// #### @str {string} String to hash.
// Utility function for creating unique ids
// e.g. Profiling incoming HTTP requests on the same tick
//
exports.hash = function (str) {
  return crypto.createHash('sha1').update(str).digest('hex');
};

//
// ## Borrowed from node.js core
// I wanted a universal lowercase header message, as opposed to the `DEBUG`
// (i.e. all uppercase header) used only in `util.debug()`
//
var months = ['Jan', 'Feb', 'Mar', 'Apr',
              'May', 'Jun', 'Jul', 'Aug',
              'Sep', 'Oct', 'Nov', 'Dec'];

//
// ### function pad (n)
// Returns a padded string if `n < 10`.
//
exports.pad = function (n) {
  return n < 10 ? '0' + n.toString(10) : n.toString(10);
};

//
// ### function timestamp ()
// Returns a timestamp string for the current time.
//
exports.timestamp = function () {
  var d = new Date();
  var time = [
    exports.pad(d.getHours()),
    exports.pad(d.getMinutes()),
    exports.pad(d.getSeconds())
  ].join(':');

  return [d.getDate(), months[d.getMonth()], time].join(' ');
};

//
// ### function serialize (obj, key)
// #### @obj {Object|literal} Object to serialize
// #### @key {string} **Optional** Optional key represented by obj in a larger object
// Performs simple comma-separated, `key=value` serialization for Loggly when
// logging to non-JSON inputs.
//
exports.serialize = function (obj, key) {
  if (obj === null) {
    obj = 'null';
  }
  else if (obj === undefined) {
    obj = 'undefined';
  }
  else if (obj === false) {
    obj = 'false';
  }

  if (typeof obj !== 'object') {
    return key ? key + '=' + obj : obj;
  }

  var msg = '',
      keys = Object.keys(obj),
      length = keys.length;

  for (var i = 0; i < length; i++) {
    if (Array.isArray(obj[keys[i]])) {
      msg += keys[i] + '=['

      for (var j = 0, l = obj[keys[i]].length; j < l; j++) {
        msg += common.serialize(obj[keys[i]][j]);
        if (j < l - 1) {
          msg += ', ';
        }
      }

      msg += ']';
    }
    else {
      msg += common.serialize(obj[keys[i]], keys[i]);
    }

    if (i < length - 1) {
      msg += ', ';
    }
  }

  return msg;
};
<|endoftext|>


<commit_before>/*
 * logger.js: Core logger object used by winston.
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENCE
 *
 */

var events = require('events'),
    util = require('util'),
    async = require('async'),
    config = require('./config'),
    common = require('./common'),
    exception = require('./exception');

//
// Time constants
//
var ticksPerMillisecond = 10000;

//
// ### function Logger (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Logger object responsible
// for persisting log messages and metadata to one or more transports.
//
var Logger = exports.Logger = function (options) {
  events.EventEmitter.call(this);
  options = options || {};

  var self = this,
      handleExceptions = false;

  //
  // Set Levels and default logging level
  //
  this.padLevels = options.padLevels || false;
  this.setLevels(options.levels);

  //
  // Setup other intelligent default settings.
  //
  this.level             = options.level || 'info';
  this.emitErrs          = options.emitErrs || false;
  this.stripColors       = options.stripColors || false;
  this.transports        = {};
  this.exceptionHandlers = {};
  this.profilers         = {};
  this._names            = [];
  this._hnames           = [];

  if (options.transports) {
    options.transports.forEach(function (transport) {
      self.add(transport, null, true);

      if (transport.handleExceptions) {
        handleExceptions = true;
      }
    });
  }

  if (options.exceptionHandlers) {
    options.exceptionHandlers.forEach(function (handler) {
      self._hnames.push(handler.name);
      self.exceptionHandlers[handler.name] = handler;
    });
  }

  if (options.handleExceptions || handleExceptions) {
    this.handleExceptions();
  }
};

//
// Inherit from `events.EventEmitter`.
//
util.inherits(Logger, events.EventEmitter);

//
// ### function extend (target)
// #### @target {Object} Target to extend.
// Extends the target object with a 'log' method
// along with a method for each level in this instance.
//
Logger.prototype.extend = function (target) {
  var self = this;
  ['log', 'profile'].concat(Object.keys(this.levels)).forEach(function (method) {
    target[method] = function () {
      return self[method].apply(self, arguments);
    };
  });

  return this;
};

//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Level at which to log the message.
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Metadata is optional.
//
Logger.prototype.log = function (level, msg) {
  var self = this,
      callback,
      meta;

  if (arguments.length === 3) {
    if (typeof arguments[2] === 'function') {
      meta = {};
      callback = arguments[2];
    }
    else if (typeof arguments[2] === 'object') {
      meta = arguments[2];
    }
  }
  else if (arguments.length === 4) {
    meta = arguments[2];
    callback = arguments[3];
  }

  // If we should pad for levels, do so
  if (this.padLevels) {
    msg = new Array(this.levelLength - level.length).join(' ') + msg;
  }

  function onError (err) {
    if (callback) {
      callback(err);
    }
    else if (self.emitErrs) {
      self.emit('error', err);
    };
  }

  if (this.transports.length === 0) {
    return onError(new Error('Cannot log with no transports.'));
  }
  else if (typeof self.levels[level] === 'undefined') {
    return onError(new Error('Unknown log level: ' + level));
  }

  //
  // For consideration of terminal 'color" programs like colors.js,
  // which can add ANSI escape color codes to strings, we destyle the
  // ANSI color escape codes when `this.stripColors` is set.
  //
  // see: http://en.wikipedia.org/wiki/ANSI_escape_code
  //
  if (this.stripColors) {
    var code = /\u001b\[\d+m/g;
    msg = ('' + msg).replace(code, '');
  }

  for (var i = 0, l = this._names.length; i < l; i++) {
    var transport = this.transports[this._names[i]];
    if ((transport.level && self.levels[transport.level] <= self.levels[level])
      || (!transport.level && self.levels[self.level] <= self.levels[level])) {
      transport.log(level, msg, meta, function (err) {
        self.emit('logging', transport, level, msg, meta);
      });
    }
  }

  //
  // Immediately respond to the callback
  //
  if (callback) {
    callback(null, level, msg, meta);
  }

  return this;
};

//
// ### function close ()
// Cleans up resources (streams, event listeners) for all
// transports associated with this instance (if necessary).
//
Logger.prototype.close = function () {
  var self = this;

  this._names.forEach(function (name) {
    var transport = self.transports[name];
    if (transport && transport.close) {
      transport.close();
    }
  });
};

//
// ### function handleExceptions ()
// Handles `uncaughtException` events for the current process
//
Logger.prototype.handleExceptions = function () {
  var args = Array.prototype.slice.call(arguments),
      handlers = [],
      self = this;

  args.forEach(function (a) {
    if (Array.isArray(a)) {
      handlers = handlers.concat(a);
    }
    else {
      handlers.push(a);
    }
  });

  handlers.forEach(function (handler) {
    self.exceptionHandlers[handler.name] = handler;
  });

  this._hnames = Object.keys(self.exceptionHandlers);

  if (!this.catchExceptions) {
    this.catchExceptions = this._uncaughtException.bind(this);
    process.on('uncaughtException', this.catchExceptions);
  }
};

//
// ### function unhandleExceptions ()
// Removes any handlers to `uncaughtException` events
// for the current process
//
Logger.prototype.unhandleExceptions = function () {
  var self = this;

  if (this.catchExceptions) {
    Object.keys(this.exceptionHandlers).forEach(function (name) {
      if (handler.close) {
        handler.close();
      }
    });

    this.exceptionHandlers = {};
    Object.keys(this.transports).forEach(function (name) {
      var transport = self.transports[name];
      if (transport.handleExceptions) {
        transport.handleExceptions = false;
      }
    })

    process.removeListener('uncaughtException', this.catchExceptions);
    this.catchExceptions = false;
  }
};

//
// ### function add (transport, [options])
// #### @transport {Transport} Prototype of the Transport object to add.
// #### @options {Object} **Optional** Options for the Transport to add.
// #### @instance {Boolean} **Optional** Value indicating if `transport` is already instantiated.
// Adds a transport of the specified type to this instance.
//
Logger.prototype.add = function (transport, options, created) {
  var instance = created ? transport : (new (transport)(options));

  if (!instance.name && !instance.log) {
    throw new Error('Unknown transport with no log() method');
  }
  else if (this.transports[instance.name]) {
    throw new Error('Transport already attached: ' + instance.name);
  }

  this.transports[instance.name] = instance;
  this._names = Object.keys(this.transports);

  //
  // Listen for the `error` event on the new Transport
  //
  instance._onError = this._onError.bind(this, instance)
  instance.on('error', instance._onError);

  return this;
};

//
// ### function remove (transport)
// #### @transport {Transport} Transport to remove.
// Removes a transport of the specified type from this instance.
//
Logger.prototype.remove = function (transport) {
  var name = transport.name || transport.prototype.name;

  if (!this.transports[name]) {
    throw new Error('Transport ' + name + ' not attached to this instance');
  }

  var instance = this.transports[name];
  delete this.transports[name];
  this._names = Object.keys(this.transports);

  if (instance.close) {
    instance.close();
  }

  instance.removeListener('error', instance._onError);
  return this;
};

//
// ### function profile (id, [msg, meta, callback])
// #### @id {string} Unique id of the profiler
// #### @msg {string} **Optional** Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Tracks the time inbetween subsequent calls to this method
// with the same `id` parameter. The second call to this method
// will log the difference in milliseconds along with the message.
//
Logger.prototype.profile = function (id) {
  var now = Date.now(), then, args,
      msg, meta, callback;

  if (this.profilers[id] && arguments.length !== 1) {
    then = this.profilers[id];
    delete this.profilers[id];

    // Support variable arguments: msg, meta, callback
    args     = Array.prototype.slice.call(arguments);
    callback = typeof args[args.length - 1] === 'function' ? args.pop() : null;
    meta     = typeof args[args.length - 1] === 'object' ? args.pop() : {};
    msg      = args.length === 2 ? args[1] : id;

    // Set the duration property of the metadata
    meta.duration = now - then + 'ms';
    return this.info(msg, meta, callback);
  }
  else {
    this.profilers[id] = now;
  }

  return this;
};

//
// ### function setLevels (target)
// #### @target {Object} Target levels to use on this instance
// Sets the `target` levels specified on this instance.
//
Logger.prototype.setLevels = function (target) {
  return common.setLevels(this, this.levels, target);
};

//
// ### function cli ()
// Configures this instance to have the default
// settings for command-line interfaces: no timestamp,
// colors enabled, padded output, and additional levels.
//
Logger.prototype.cli = function () {
  this.padLevels = true;
  this.setLevels(config.cli.levels);
  config.addColors(config.cli.colors);

  if (this.transports.console) {
    this.transports.console.colorize = true;
    this.transports.console.timestamp = false;
  }

  return this;
};

//
// ### @private function _uncaughtException (err)
// #### @err {Error} Error to handle
// Logs all relevant information around the `err` and
// exits the current process.
//
Logger.prototype._uncaughtException = function (err) {
  var self = this,
      responded = false,
      info = exception.getAllInfo(err),
      handlers = this._getExceptionHandlers(),
      timeout;

  function logAndWait (transport, next) {
    transport.logException('uncaughtException', info, next);
  }

  function gracefulExit () {
    if (!responded) {
      //
      // Remark: Currently ignoring any exceptions from transports
      //         when catching uncaught exceptions.
      //
      clearTimeout(timeout);
      responded = true;
      process.exit(1);
    }
  }

  if (!handlers || handlers.length === 0) {
    return gracefulExit();
  }

  //
  // Log to all transports and allow the operation to take
  // only up to `3000ms`.
  //
  async.forEach(handlers, logAndWait, gracefulExit);
  timeout = setTimeout(gracefulExit, 3000);
};

//
// ### @private function _getExceptionHandlers ()
// Returns the list of transports and exceptionHandlers
// for this instance.
//
Logger.prototype._getExceptionHandlers = function () {
  var self = this;

  return this._hnames.map(function (name) {
    return self.exceptionHandlers[name];
  }).concat(this._names.map(function (name) {
    return self.transports[name].handleExceptions && self.transports[name];
  })).filter(Boolean);
};

//
// ### @private function _onError (transport, err)
// #### @transport {Object} Transport on which the error occured
// #### @err {Error} Error that occurred on the transport
// Bubbles the error, `err`, that occured on the specified `transport`
// up from this instance if `emitErrs` has been set.
//
Logger.prototype._onError = function (transport, err) {
  if (self.emitErrs) {
    self.emit('error', err, transport);
  }
};<commit_msg>[fix] Update bad self reference<commit_after>/*
 * logger.js: Core logger object used by winston.
 *
 * (C) 2010 Charlie Robbins
 * MIT LICENCE
 *
 */

var events = require('events'),
    util = require('util'),
    async = require('async'),
    config = require('./config'),
    common = require('./common'),
    exception = require('./exception');

//
// Time constants
//
var ticksPerMillisecond = 10000;

//
// ### function Logger (options)
// #### @options {Object} Options for this instance.
// Constructor function for the Logger object responsible
// for persisting log messages and metadata to one or more transports.
//
var Logger = exports.Logger = function (options) {
  events.EventEmitter.call(this);
  options = options || {};

  var self = this,
      handleExceptions = false;

  //
  // Set Levels and default logging level
  //
  this.padLevels = options.padLevels || false;
  this.setLevels(options.levels);

  //
  // Setup other intelligent default settings.
  //
  this.level             = options.level || 'info';
  this.emitErrs          = options.emitErrs || false;
  this.stripColors       = options.stripColors || false;
  this.transports        = {};
  this.exceptionHandlers = {};
  this.profilers         = {};
  this._names            = [];
  this._hnames           = [];

  if (options.transports) {
    options.transports.forEach(function (transport) {
      self.add(transport, null, true);

      if (transport.handleExceptions) {
        handleExceptions = true;
      }
    });
  }

  if (options.exceptionHandlers) {
    options.exceptionHandlers.forEach(function (handler) {
      self._hnames.push(handler.name);
      self.exceptionHandlers[handler.name] = handler;
    });
  }

  if (options.handleExceptions || handleExceptions) {
    this.handleExceptions();
  }
};

//
// Inherit from `events.EventEmitter`.
//
util.inherits(Logger, events.EventEmitter);

//
// ### function extend (target)
// #### @target {Object} Target to extend.
// Extends the target object with a 'log' method
// along with a method for each level in this instance.
//
Logger.prototype.extend = function (target) {
  var self = this;
  ['log', 'profile'].concat(Object.keys(this.levels)).forEach(function (method) {
    target[method] = function () {
      return self[method].apply(self, arguments);
    };
  });

  return this;
};

//
// ### function log (level, msg, [meta], callback)
// #### @level {string} Level at which to log the message.
// #### @msg {string} Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} Continuation to respond to when complete.
// Core logging method exposed to Winston. Metadata is optional.
//
Logger.prototype.log = function (level, msg) {
  var self = this,
      callback,
      meta;

  if (arguments.length === 3) {
    if (typeof arguments[2] === 'function') {
      meta = {};
      callback = arguments[2];
    }
    else if (typeof arguments[2] === 'object') {
      meta = arguments[2];
    }
  }
  else if (arguments.length === 4) {
    meta = arguments[2];
    callback = arguments[3];
  }

  // If we should pad for levels, do so
  if (this.padLevels) {
    msg = new Array(this.levelLength - level.length).join(' ') + msg;
  }

  function onError (err) {
    if (callback) {
      callback(err);
    }
    else if (self.emitErrs) {
      self.emit('error', err);
    };
  }

  if (this.transports.length === 0) {
    return onError(new Error('Cannot log with no transports.'));
  }
  else if (typeof self.levels[level] === 'undefined') {
    return onError(new Error('Unknown log level: ' + level));
  }

  //
  // For consideration of terminal 'color" programs like colors.js,
  // which can add ANSI escape color codes to strings, we destyle the
  // ANSI color escape codes when `this.stripColors` is set.
  //
  // see: http://en.wikipedia.org/wiki/ANSI_escape_code
  //
  if (this.stripColors) {
    var code = /\u001b\[\d+m/g;
    msg = ('' + msg).replace(code, '');
  }

  for (var i = 0, l = this._names.length; i < l; i++) {
    var transport = this.transports[this._names[i]];
    if ((transport.level && self.levels[transport.level] <= self.levels[level])
      || (!transport.level && self.levels[self.level] <= self.levels[level])) {
      transport.log(level, msg, meta, function (err) {
        self.emit('logging', transport, level, msg, meta);
      });
    }
  }

  //
  // Immediately respond to the callback
  //
  if (callback) {
    callback(null, level, msg, meta);
  }

  return this;
};

//
// ### function close ()
// Cleans up resources (streams, event listeners) for all
// transports associated with this instance (if necessary).
//
Logger.prototype.close = function () {
  var self = this;

  this._names.forEach(function (name) {
    var transport = self.transports[name];
    if (transport && transport.close) {
      transport.close();
    }
  });
};

//
// ### function handleExceptions ()
// Handles `uncaughtException` events for the current process
//
Logger.prototype.handleExceptions = function () {
  var args = Array.prototype.slice.call(arguments),
      handlers = [],
      self = this;

  args.forEach(function (a) {
    if (Array.isArray(a)) {
      handlers = handlers.concat(a);
    }
    else {
      handlers.push(a);
    }
  });

  handlers.forEach(function (handler) {
    self.exceptionHandlers[handler.name] = handler;
  });

  this._hnames = Object.keys(self.exceptionHandlers);

  if (!this.catchExceptions) {
    this.catchExceptions = this._uncaughtException.bind(this);
    process.on('uncaughtException', this.catchExceptions);
  }
};

//
// ### function unhandleExceptions ()
// Removes any handlers to `uncaughtException` events
// for the current process
//
Logger.prototype.unhandleExceptions = function () {
  var self = this;

  if (this.catchExceptions) {
    Object.keys(this.exceptionHandlers).forEach(function (name) {
      if (handler.close) {
        handler.close();
      }
    });

    this.exceptionHandlers = {};
    Object.keys(this.transports).forEach(function (name) {
      var transport = self.transports[name];
      if (transport.handleExceptions) {
        transport.handleExceptions = false;
      }
    })

    process.removeListener('uncaughtException', this.catchExceptions);
    this.catchExceptions = false;
  }
};

//
// ### function add (transport, [options])
// #### @transport {Transport} Prototype of the Transport object to add.
// #### @options {Object} **Optional** Options for the Transport to add.
// #### @instance {Boolean} **Optional** Value indicating if `transport` is already instantiated.
// Adds a transport of the specified type to this instance.
//
Logger.prototype.add = function (transport, options, created) {
  var instance = created ? transport : (new (transport)(options));

  if (!instance.name && !instance.log) {
    throw new Error('Unknown transport with no log() method');
  }
  else if (this.transports[instance.name]) {
    throw new Error('Transport already attached: ' + instance.name);
  }

  this.transports[instance.name] = instance;
  this._names = Object.keys(this.transports);

  //
  // Listen for the `error` event on the new Transport
  //
  instance._onError = this._onError.bind(this, instance)
  instance.on('error', instance._onError);

  return this;
};

//
// ### function remove (transport)
// #### @transport {Transport} Transport to remove.
// Removes a transport of the specified type from this instance.
//
Logger.prototype.remove = function (transport) {
  var name = transport.name || transport.prototype.name;

  if (!this.transports[name]) {
    throw new Error('Transport ' + name + ' not attached to this instance');
  }

  var instance = this.transports[name];
  delete this.transports[name];
  this._names = Object.keys(this.transports);

  if (instance.close) {
    instance.close();
  }

  instance.removeListener('error', instance._onError);
  return this;
};

//
// ### function profile (id, [msg, meta, callback])
// #### @id {string} Unique id of the profiler
// #### @msg {string} **Optional** Message to log
// #### @meta {Object} **Optional** Additional metadata to attach
// #### @callback {function} **Optional** Continuation to respond to when complete.
// Tracks the time inbetween subsequent calls to this method
// with the same `id` parameter. The second call to this method
// will log the difference in milliseconds along with the message.
//
Logger.prototype.profile = function (id) {
  var now = Date.now(), then, args,
      msg, meta, callback;

  if (this.profilers[id] && arguments.length !== 1) {
    then = this.profilers[id];
    delete this.profilers[id];

    // Support variable arguments: msg, meta, callback
    args     = Array.prototype.slice.call(arguments);
    callback = typeof args[args.length - 1] === 'function' ? args.pop() : null;
    meta     = typeof args[args.length - 1] === 'object' ? args.pop() : {};
    msg      = args.length === 2 ? args[1] : id;

    // Set the duration property of the metadata
    meta.duration = now - then + 'ms';
    return this.info(msg, meta, callback);
  }
  else {
    this.profilers[id] = now;
  }

  return this;
};

//
// ### function setLevels (target)
// #### @target {Object} Target levels to use on this instance
// Sets the `target` levels specified on this instance.
//
Logger.prototype.setLevels = function (target) {
  return common.setLevels(this, this.levels, target);
};

//
// ### function cli ()
// Configures this instance to have the default
// settings for command-line interfaces: no timestamp,
// colors enabled, padded output, and additional levels.
//
Logger.prototype.cli = function () {
  this.padLevels = true;
  this.setLevels(config.cli.levels);
  config.addColors(config.cli.colors);

  if (this.transports.console) {
    this.transports.console.colorize = true;
    this.transports.console.timestamp = false;
  }

  return this;
};

//
// ### @private function _uncaughtException (err)
// #### @err {Error} Error to handle
// Logs all relevant information around the `err` and
// exits the current process.
//
Logger.prototype._uncaughtException = function (err) {
  var self = this,
      responded = false,
      info = exception.getAllInfo(err),
      handlers = this._getExceptionHandlers(),
      timeout;

  function logAndWait (transport, next) {
    transport.logException('uncaughtException', info, next);
  }

  function gracefulExit () {
    if (!responded) {
      //
      // Remark: Currently ignoring any exceptions from transports
      //         when catching uncaught exceptions.
      //
      clearTimeout(timeout);
      responded = true;
      process.exit(1);
    }
  }

  if (!handlers || handlers.length === 0) {
    return gracefulExit();
  }

  //
  // Log to all transports and allow the operation to take
  // only up to `3000ms`.
  //
  async.forEach(handlers, logAndWait, gracefulExit);
  timeout = setTimeout(gracefulExit, 3000);
};

//
// ### @private function _getExceptionHandlers ()
// Returns the list of transports and exceptionHandlers
// for this instance.
//
Logger.prototype._getExceptionHandlers = function () {
  var self = this;

  return this._hnames.map(function (name) {
    return self.exceptionHandlers[name];
  }).concat(this._names.map(function (name) {
    return self.transports[name].handleExceptions && self.transports[name];
  })).filter(Boolean);
};

//
// ### @private function _onError (transport, err)
// #### @transport {Object} Transport on which the error occured
// #### @err {Error} Error that occurred on the transport
// Bubbles the error, `err`, that occured on the specified `transport`
// up from this instance if `emitErrs` has been set.
//
Logger.prototype._onError = function (transport, err) {
  if (this.emitErrs) {
    this.emit('error', err, transport);
  }
};<|endoftext|>