<commit_before>var Sim900r = function(options) {
  if (!options) {
    options = {};
  }
  this._debug = options.debug || false;
  this._powerPin = options.powerPin || P2;
  this._statusPin = options.statusPin || P3;

  this._serial = options.port || Serial3;
  this._serial.setup(options.serialSpeed || 9600);

  this._smsEvent = false;
  this._smsPhone = undefined;
  this._smsDate = undefined;
  this._smsText = undefined;

  this._currentCommand = null;
  this._currentCommandData = [];
  this._currentCommandCallback = undefined;
  this._currentCommandResponse = false;

  var self = this;

  /**
   * Настройка триггера пина статуса
   */
  pinMode(this._statusPin, 'input_pulldown');
  setWatch(function(e) {
    if (e.state === true) {
      self.emit('powerOn');
    } else {
      self.emit('powerOff');
    }
  }, this._statusPin, {
    repeat: true,
    edge: 'both',
    debounce: 10
  });

  /**
   * При поступлении данные на порт, суммируем их в буффер
   * и разделяем по переходу на новую строку, после чего
   * обрабатываем их построчно.
   */
  var dataBuffer = '';
  this._serial.on('data', function(data) {
    dataBuffer += data;
    var lines = dataBuffer.split('\r\n');
    for (var i = 0; i < lines.length - 1; i++) {
      if (lines[i] !== '') {
        self._onDataLine(lines[i]);
      }
    }
    dataBuffer = lines[lines.length - 1];
  });
};

Sim900r.prototype._onDataLine = function(line) {
  var data = line.split(': ');
  switch (data[0]) {
    case 'RING':
      this.emit('ring');
      break;
    case '+CLIP':
      this.emit('clip', this.parsePhone(data[1]));
      break;
    case 'NO CARRIER':
      this.emit('noCarrier');
      break;
    case 'BUSY':
      this.emit('busy');
      break;
    case '+CUSD':
      this.emit('ussd',data[1]);
      break;
    case '+CMTI':
      var index = parseInt(data[1].split(',')[1]);
      this.emit('sms', index);
      break;
    case '+CPIN':
      if (data[1] === 'READY') {
        this.emit('simReady');
      } else if (data[1] === 'SIM PIN') {
        this.emit('simPin');
      } else {
        this.emit('simError', data[1]);
      }
      break;
    case 'Call Ready':
      this.emit('simNetwork');
      break;
    // Если строка равна строке запроса команды,
    // то дальше будут передаваться данные
    case this._currentCommand:
      this._currentCommandResponse = true;
      break;
    // Конец ответа на команду
    case 'OK':
      this._currentCommandResponse = false;
      this._currentCommandCallback(undefined, this._currentCommandData);
      break;
    // Ошибка при выполнении команды
    case 'ERROR':
      this._currentCommandResponse = false;
      this._currentCommandCallback(new Error('CMD Error'));
      break;
    default:
      if (this._currentCommandResponse) {
        this._currentCommandData.push(line);
      } else {
        this.emit('unknown', line);
      }
  }
};

/*
 * Стук к пину включения/выключения
 */
Sim900r.prototype.power = function() {
  digitalPulse(this._powerPin, 1, 1000);
};

/**
 * Включение модуля
 */
Sim900r.prototype.powerOn = function() {
  if (!this.isReady()) {
    this.power();
  }
};

/**
 * Выключение модуля
 */
Sim900r.prototype.powerOff = function() {
  if (this.isReady()) {
    this.power();
  }
};

/**
 * Состояние готовности к взаимодейтвию
 */
Sim900r.prototype.isReady = function() {
  return !!digitalRead(this._statusPin);
};

/**
 * Вызов команды
 */
Sim900r.prototype.cmd = function(command, callback) {
  // Нельзя отправлять новую команду, пока данные от предыдущей не получены
  if (!this.isReady()) {
    callback(new Error('powerOff'));
  } else if (!this._currentCommandResponse) {
    if (!callback) {
      callback = function() { };
    }
    this._currentCommand = command.toUpperCase();
    this._currentCommandData = [];
    this._currentCommandCallback = callback;
    this._serial.println(command);
  } else {
    if (callback) {
      callback(new Error('busy'));
    }
  }
};

/**
 * Отправка СМС на номер
 */
Sim900r.prototype.smsSend = function(phone, text, callback) {
  var serial = this._serial;
  this.cmd('AT+CMGS="' + phone + '"', callback);
  setTimeout(function() {
    serial.println(text + '\u001a');
  }, 500);
};

/**
 * Получение списка SMS
 */
Sim900r.prototype.smsList = function(callback) {
  var self = this;
  this.cmd('AT+CMGF=1', function(error, data) {
    if (!error) {
      this.cmd('AT+CMGL="ALL",1', function(error, data){
        if (!error) {
          var smsList = [];
          for (var s=0; s<data.length; s = s+2) {
            var sms = self.parseSMS(data[s], data[s+1]);
            smsList.push(sms);
          }
          callback(undefined, smsList);
        } else {
          callback(error);
        }
      });
    } else {
      callback(error);
    }
  });
};

/**
 * Чтение СМС с SIM-карты
 */
Sim900r.prototype.smsRead = function(index, callback) {
  var self = this;
  this.cmd('AT+CMGR=' + index, function(error, result) {
    if (result.length === 0) {
      callback(new Error('SMS is not found'));
    } else {
      callback(undefined, self.parseSMS(result[0], result[1], index));
    }
  });
};

/**
 * Удаление СМС с SIM-карты
 */
Sim900r.prototype.smsDelete = function(index, callback) {
  var command = 'AT+CMGD=' + index;
  if (index === 'all') {
    command = 'AT+CMGD=0,4';
  }
  this.cmd(command, function(err, result) {
    print(err, result);
  });
};

/**
 * Набор номера
 */
Sim900r.prototype.call = function(phone, callback) {
  this.cmd('ATD' + phone + ';', callback);
};

/**
 * Ответ на входящий звонок
 */
Sim900r.prototype.answer = function(callback) {
  this.cmd('ATA', callback);
};

/**
 * Разрыв соединения
 */
Sim900r.prototype.cancel = function(callback) {
  this.cmd('ATH0', callback);
};

/**
 * Отправка USSD команды
 */
Sim900r.prototype.ussd = function(phone, callback) {
  this.cmd('AT+CUSD=1,"'+phone+'"', callback);
};

/**
 * Оператор SIM-карты
 */
Sim900r.prototype.netProvider = function(callback) {
  this.cmd('AT+CSPN?', callback);
};

/**
 * Оператор, в сети которого зарегистрирована SIM-карта
 */
Sim900r.prototype.netCurrent = function(callback) {
  this.cmd('AT+COPS?', callback);
};

/**
 * Статус регистрации в сети
 */
Sim900r.prototype.netStatus = function(callback) {
  this.cmd('AT+CREG?', callback);
};

/**
 * Качество приема сигнала
 */
Sim900r.prototype.netQuality = function(callback) {
  this.cmd('AT+CSQ', callback);
};

Sim900r.prototype.imei = function(callback) {
  this.cmd('AT+GSN', function(data) {
    var imei = Sim900r.prototype.parse.first(data);
    if (callback) {
      callback(imei);
    }
  });
};

Sim900r.prototype.firmware = function(callback) {
  this.cmd('AT+GMR', function(error, data) {
    if (!error) {
      data = data[0];
    }
    callback(error, data);
  });
};

Sim900r.prototype.time = function(callback) {
  this.cmd('AT+CCLK?', function(error, data) {
    if (!error) {
      data = this.parseTime(data);
    }
    callback(error, data);
  });
};

Sim900r.prototype.setCallerID = function(val, callback) {
  this.cmd('AT+CLIP=' + val, callback);
};

Sim900r.prototype.getCallerID = function(callback) {
  this.cmd('AT+CLIP?', callback);
};

/**
 * Методы обработки ответов
 */
Sim900r.prototype.parseTime = function(data) {
  data = '20' + data[0].split('"')[1];
  return new Date(data.replace(',', 'T').replace('/', '-').replace('/', '-'));
};

Sim900r.prototype.parseSMS = function(fLine, lLine, index) {
  var data = fLine.split('\"');
  var indexData = data[0].split(': ');
  var message = {
    index: index || indexData[1],
    phone: data[3],
    datetime: this.parseTime(data[7]),
    text: lLine
  };
  return message;
};

Sim900r.prototype.parsePhone = function(phone) {
  phone = phone.split('"');
  if (phone[1]) {
    phone = phone[1];
  } else {
    phone = undefined;
  }
  return phone;
};

Sim900r.prototype.parsePhoneToPDU = function(phone) {
  phone = phone.split('');

  if (phone[0] === '+') {
    phone.splice(0, 1);
  }

  var len = phone.length;

  if (len % 2 > 0) {
    phone.push('F');
  }

  for (var c = 0; c < (phone.length / 2); c++) {
    var tmp = phone[c * 2];
    phone[c * 2] = phone[c * 2 + 1];
    phone[c * 2 + 1] = tmp;
  }

  return phone;
};

exports.connect = function(_uart, _powerPin, _statusPin) {
  return new Sim900r(_uart, _powerPin, _statusPin);
};
<commit_msg>DateTime in SMS, setTime, getTime<commit_after>var Sim900r = function(options) {
  if (!options) {
    options = {};
  }
  this._debug = options.debug || false;
  this._powerPin = options.powerPin || P2;
  this._statusPin = options.statusPin || P3;

  this._serial = options.port || Serial3;
  this._serial.setup(options.serialSpeed || 9600);

  this._smsEvent = false;
  this._smsPhone = undefined;
  this._smsDate = undefined;
  this._smsText = undefined;

  this._currentCommand = null;
  this._currentCommandData = [];
  this._currentCommandCallback = undefined;
  this._currentCommandResponse = false;

  var self = this;

  /**
   * Настройка триггера пина статуса
   */
  pinMode(this._statusPin, 'input_pulldown');
  setWatch(function(e) {
    if (e.state === true) {
      self.emit('powerOn');
    } else {
      self.emit('powerOff');
    }
  }, this._statusPin, {
    repeat: true,
    edge: 'both',
    debounce: 10
  });

  /**
   * При поступлении данные на порт, суммируем их в буффер
   * и разделяем по переходу на новую строку, после чего
   * обрабатываем их построчно.
   */
  var dataBuffer = '';
  this._serial.on('data', function(data) {
    dataBuffer += data;
    var lines = dataBuffer.split('\r\n');
    for (var i = 0; i < lines.length - 1; i++) {
      if (lines[i] !== '') {
        self._onDataLine(lines[i]);
      }
    }
    dataBuffer = lines[lines.length - 1];
  });
};

Sim900r.prototype._onDataLine = function(line) {
  var data = line.split(': ');
  switch (data[0]) {
    case 'RING':
      this.emit('ring');
      break;
    case '+CLIP':
      this.emit('clip', this.parsePhone(data[1]));
      break;
    case 'NO CARRIER':
      this.emit('noCarrier');
      break;
    case 'BUSY':
      this.emit('busy');
      break;
    case '+CUSD':
      this.emit('ussd',data[1]);
      break;
    case '+CMTI':
      var index = parseInt(data[1].split(',')[1]);
      this.emit('sms', index);
      break;
    case '+CPIN':
      if (data[1] === 'READY') {
        this.emit('simReady');
      } else if (data[1] === 'SIM PIN') {
        this.emit('simPin');
      } else {
        this.emit('simError', data[1]);
      }
      break;
    case 'Call Ready':
      this.emit('simNetwork');
      break;
    // Если строка равна строке запроса команды,
    // то дальше будут передаваться данные
    case this._currentCommand:
      this._currentCommandResponse = true;
      break;
    // Конец ответа на команду
    case 'OK':
      this._currentCommandResponse = false;
      this._currentCommandCallback(undefined, this._currentCommandData);
      break;
    // Ошибка при выполнении команды
    case 'ERROR':
      this._currentCommandResponse = false;
      this._currentCommandCallback(new Error('CMD Error'));
      break;
    default:
      if (this._currentCommandResponse) {
        this._currentCommandData.push(line);
      } else {
        this.emit('unknown', line);
      }
  }
};

/*
 * Стук к пину включения/выключения
 */
Sim900r.prototype.power = function() {
  digitalPulse(this._powerPin, 1, 1000);
};

/**
 * Включение модуля
 */
Sim900r.prototype.powerOn = function() {
  if (!this.isReady()) {
    this.power();
  }
};

/**
 * Выключение модуля
 */
Sim900r.prototype.powerOff = function() {
  if (this.isReady()) {
    this.power();
  }
};

/**
 * Состояние готовности к взаимодейтвию
 */
Sim900r.prototype.isReady = function() {
  return !!digitalRead(this._statusPin);
};

/**
 * Вызов команды
 */
Sim900r.prototype.cmd = function(command, callback) {
  // Нельзя отправлять новую команду, пока данные от предыдущей не получены
  if (!this.isReady()) {
    callback(new Error('powerOff'));
  } else if (!this._currentCommandResponse) {
    if (!callback) {
      callback = function() { };
    }
    this._currentCommand = command.toUpperCase();
    this._currentCommandData = [];
    this._currentCommandCallback = callback;
    this._serial.println(command);
  } else {
    if (callback) {
      callback(new Error('busy'));
    }
  }
};

/**
 * Отправка СМС на номер
 */
Sim900r.prototype.smsSend = function(phone, text, callback) {
  var serial = this._serial;
  this.cmd('AT+CMGS="' + phone + '"', callback);
  setTimeout(function() {
    serial.println(text + '\u001a');
  }, 500);
};

/**
 * Получение списка SMS
 */
Sim900r.prototype.smsList = function(callback) {
  var self = this;
  this.cmd('AT+CMGF=1', function(error, data) {
    if (!error) {
      this.cmd('AT+CMGL="ALL",1', function(error, data){
        if (!error) {
          var smsList = [];
          for (var s=0; s<data.length; s = s+2) {
            var sms = self.parseSMS(data[s], data[s+1]);
            smsList.push(sms);
          }
          callback(undefined, smsList);
        } else {
          callback(error);
        }
      });
    } else {
      callback(error);
    }
  });
};

/**
 * Чтение СМС с SIM-карты
 */
Sim900r.prototype.smsRead = function(index, callback) {
  var self = this;
  this.cmd('AT+CMGR=' + index, function(error, result) {
    if (result.length === 0) {
      callback(new Error('SMS is not found'));
    } else {
      callback(undefined, self.parseSMS(result[0], result[1], index));
    }
  });
};

/**
 * Удаление СМС с SIM-карты
 */
Sim900r.prototype.smsDelete = function(index, callback) {
  var command = 'AT+CMGD=' + index;
  if (index === 'all') {
    command = 'AT+CMGD=0,4';
  }
  this.cmd(command, function(err, result) {
    print(err, result);
  });
};

/**
 * Набор номера
 */
Sim900r.prototype.call = function(phone, callback) {
  this.cmd('ATD' + phone + ';', callback);
};

/**
 * Ответ на входящий звонок
 */
Sim900r.prototype.answer = function(callback) {
  this.cmd('ATA', callback);
};

/**
 * Разрыв соединения
 */
Sim900r.prototype.cancel = function(callback) {
  this.cmd('ATH0', callback);
};

/**
 * Отправка USSD команды
 */
Sim900r.prototype.ussd = function(phone, callback) {
  this.cmd('AT+CUSD=1,"'+phone+'"', callback);
};

/**
 * Оператор SIM-карты
 */
Sim900r.prototype.netProvider = function(callback) {
  this.cmd('AT+CSPN?', callback);
};

/**
 * Оператор, в сети которого зарегистрирована SIM-карта
 */
Sim900r.prototype.netCurrent = function(callback) {
  this.cmd('AT+COPS?', callback);
};

/**
 * Статус регистрации в сети
 */
Sim900r.prototype.netStatus = function(callback) {
  this.cmd('AT+CREG?', callback);
};

/**
 * Качество приема сигнала
 */
Sim900r.prototype.netQuality = function(callback) {
  this.cmd('AT+CSQ', callback);
};

Sim900r.prototype.getImei = function(callback) {
  this.cmd('AT+GSN', function(data) {
    var imei = Sim900r.prototype.parse.first(data);
    if (callback) {
      callback(imei);
    }
  });
};

Sim900r.prototype.getFirmware = function(callback) {
  this.cmd('AT+GMR', function(error, data) {
    if (!error) {
      data = data[0];
    }
    callback(error, data);
  });
};

Sim900r.prototype.getTime = function(callback) {
  this.cmd('AT+CCLK?', function(error, data) {
    if (!error) {
      var date = this.parseSimDateToDate(data[0].split('"')[1]);
      callback(undefined, date);
    } else {
      callback(error);
    }
  });
};

Sim900r.prototype.setTime = function(dt, callback) {
  var date = this.parseDateToSimDate(dt);
  this.cmd('AT+CCLK="'+date+'"', callback);
};

Sim900r.prototype.setCallerID = function(val, callback) {
  this.cmd('AT+CLIP=' + val, callback);
};

Sim900r.prototype.getCallerID = function(callback) {
  this.cmd('AT+CLIP?', callback);
};

/**
 * Методы обработки ответов
 */

Sim900r.prototype.parseSMS = function(fLine, lLine, index) {
  var data = fLine.split('\"');
  var indexData = data[0].split(': ');
  var message = {
    index: index || indexData[1],
    phone: data[3],
    date: this.parseSimDateToDate(data[7]),
    text: lLine
  };
  return message;
};

Sim900r.prototype.parsePhone = function(phone) {
  phone = phone.split('"');
  if (phone[1]) {
    phone = phone[1];
  } else {
    phone = undefined;
  }
  return phone;
};

Sim900r.prototype.parseDateToSimDate = function(dt) {
  var year = (dt.getFullYear()+'').substr(-2);
  var month = ('0' + dt.getMonth()).substr(-2,2);
  var day = ('0' + dt.getDate()).substr(-2,2);
  var hh = ('0' + dt.getHours()).substr(-2,2);
  var mm = ('0' + dt.getMinutes()).substr(-2,2);
  var ss = ('0' + dt.getSeconds()).substr(-2,2);
  var date = year+'/'+month+'/'+day+','+hh+':'+mm+':'+ss+'+00';
  return date;
};

Sim900r.prototype.parseSimDateToDate = function(dt) {
  // 00/01/01,07:51:29+00
  var date = '20'+dt.substr(0,2)+'-'+dt.substr(3,2)+'-'+dt.substr(6,2)+'T';
  date += dt.substr(9,2)+':'+dt.substr(12,2)+':'+dt.substr(15,2);
  return new Date(Date.parse(date));
};

Sim900r.prototype.parsePhoneToPDU = function(phone) {
  phone = phone.split('');

  if (phone[0] === '+') {
    phone.splice(0, 1);
  }

  var len = phone.length;

  if (len % 2 > 0) {
    phone.push('F');
  }

  for (var c = 0; c < (phone.length / 2); c++) {
    var tmp = phone[c * 2];
    phone[c * 2] = phone[c * 2 + 1];
    phone[c * 2 + 1] = tmp;
  }

  return phone;
};

exports.connect = function(_uart, _powerPin, _statusPin) {
  return new Sim900r(_uart, _powerPin, _statusPin);
};
<|endoftext|>


<commit_before>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import FormattedMessage from './FormattedMessage';
import List from './List';
import ListItem from './ListItem';
import CSSClassnames from '../utils/CSSClassnames';
import Announcer from '../utils/Announcer';

const CLASS_ROOT = CSSClassnames.LEGEND;
const COLOR_INDEX = CSSClassnames.COLOR_INDEX;

function getMaxDecimalDigits(series) {
  let maxDigits = 0;
  series.forEach((item) => {
    const currentDigitsGroup = /\.(\d*)$/.exec(item.value.toString());
    if (currentDigitsGroup) {
      const currentDigits = currentDigitsGroup[1].length;
      maxDigits = Math.max(maxDigits, currentDigits);
    }
  });

  return Math.pow(10, maxDigits);
}

export default class Legend extends Component {

  constructor(props, context) {
    super(props, context);

    this._onActive = this._onActive.bind(this);
    this._renderSeries = this._renderSeries.bind(this);
    this._renderSwatch = this._renderSwatch.bind(this);
    this._renderLabel = this._renderLabel.bind(this);
    this._renderValue = this._renderValue.bind(this);
    this._renderTotal = this._renderTotal.bind(this);
    this._seriesTotal = this._seriesTotal.bind(this);

    this.state = {activeIndex: this.props.activeIndex};
  }

  componentWillReceiveProps (newProps) {
    if (newProps.activeIndex !== this.state.activeIndex) {
      this.setState({activeIndex: newProps.activeIndex});
    }
  }

  componentDidUpdate () {
    const { announce } = this.props;
    if (announce) {
      Announcer.announce(this.legendRef.textContent);
    }
  }

  _onActive (index) {
    const { onActive } = this.props;
    this.setState({activeIndex: index});
    if (onActive) {
      onActive(index);
    }
  }

  _itemColorIndex (item, index) {
    return item.colorIndex || `graph-${index + 1}`;
  }

  _renderSwatch (item, index) {
    const colorIndex = this._itemColorIndex(item, index);
    return (
      <svg className={
          `${CLASS_ROOT}__item-swatch ${COLOR_INDEX}-${colorIndex}`
        } viewBox="0 0 12 12">
        <path className={item.className} d="M 5 0 l 0 12" />
      </svg>
    );
  }

  _renderLabel (item, swatch) {
    if (swatch) {
      return (
        <span className={`${CLASS_ROOT}__item-label`}>
          {swatch}
          {item.label}

      );
    } else {
      return (
        <span className={`${CLASS_ROOT}__item-label`}>{item.label}
      );
    }
  }

  _renderValue (item) {
    const { units } = this.props;
    const unitsValue = item.units || units;
    const valueClasses = `${CLASS_ROOT}__item-value`;
    let unitsPrefix;
    let unitsSuffix;
    if (unitsValue) {
      if (unitsValue.prefix) {
        unitsPrefix = (
          <span className={`${CLASS_ROOT}__item-units`}>
            {unitsValue.prefix}

        );
      }
      if (unitsValue.suffix ||
        (typeof unitsValue === 'string' || unitsValue instanceof String)) {
        unitsSuffix = (
          <span className={`${CLASS_ROOT}__item-units`}>
            {unitsValue.suffix || unitsValue}

        );
      }
    }
    return (

        {unitsPrefix}
        {item.value}
        {unitsSuffix}

    );
  }

  _seriesTotal () {
    const { series } = this.props;
    const maxDecimalDigits = getMaxDecimalDigits(series);
    let total = 0;
    series.forEach(item =>
      total += (typeof item.value === 'number' ?
       item.value : 0) * maxDecimalDigits );
    return total / maxDecimalDigits;
  }

  _renderSeries () {
    const { series } = this.props;
    const { activeIndex } = this.state;

    return series.map((item, index) => {
      const legendClasses = classnames(
        `${CLASS_ROOT}__item`, {
          [`${CLASS_ROOT}__item--active`]: index === activeIndex,
          [`${CLASS_ROOT}__item--clickable`]: item.onClick
        }
      );

      let swatch;
      if (item.hasOwnProperty('colorIndex')) {
        swatch = this._renderSwatch(item, index);
      }

      let label;
      if (item.hasOwnProperty('label')) {
        label = this._renderLabel(item, swatch);
      }

      let value;
      if (item.hasOwnProperty('value')) {
        value = this._renderValue(item);
      }

      return (
        <ListItem onClick={item.onClick} justify='between'
          separator='none' pad={{ horizontal: 'small' }}
          key={item.label || index} className={legendClasses}
          onMouseOver={this._onActive.bind(this, index)}
          onMouseOut={this._onActive.bind(this, undefined)} >
          {label}
          {value}
        </ListItem>
      );
    }, this);
  }

  _renderTotal () {
    const { total, units } = this.props;
    let totalValue;
    if (total !== true) {
      totalValue = total;
    } else {
      totalValue = this._seriesTotal();
    }
    let unitsPrefix;
    let unitsSuffix;
    if (units && units.prefix) {
      unitsPrefix = (
        <span className={`${CLASS_ROOT}__total-units`}>
          {units.prefix}

      );
    }
    if (units &&
      (units.suffix ||
        (typeof units === 'string' ||
        units instanceof String))) {
      unitsSuffix = (
        <span className={`${CLASS_ROOT}__total-units`}>
          {units.suffix || units}

      );
    }

    return (
      <ListItem className={`${CLASS_ROOT}__total`}
        justify='between' separator='none' pad={{ horizontal: 'small' }}>
        <span className={`${CLASS_ROOT}__total-label`}>
          <FormattedMessage id="Total" defaultMessage="Total" />

        <span className={`${CLASS_ROOT}__total-value`}>
          {unitsPrefix}
          {totalValue}
          {unitsSuffix}

      </ListItem>
    );
  }

  render () {
    const { className, series, total, ...props } = this.props;
    delete props.activeIndex;
    delete props.announce;
    delete props.onActive;
    delete props.units;

    const classes = classnames(
      CLASS_ROOT,
      className
    );

    let items = this._renderSeries();

    // build legend from bottom to top, to align with Meter bar stacking
    items.reverse();

    let totalNode;
    if (total && series.length > 1) {
      totalNode = this._renderTotal();
    }

    return (
      <List ref={ref => this.legendRef = ref} {...props} className={classes}>
        {items.reverse()}
        {totalNode}
      </List>
    );
  }

}

Legend.defaultProps = {
  announce: false
};

Legend.propTypes = {
  activeIndex: PropTypes.number,
  announce: PropTypes.bool,
  onActive: PropTypes.func,
  series: PropTypes.arrayOf(PropTypes.shape({
    label: PropTypes.string,
    value: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.node
    ]),
    units: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.shape({
        prefix: PropTypes.string,
        suffix: PropTypes.string
      })
    ]),
    colorIndex: PropTypes.oneOfType([
      PropTypes.number, // 1-6
      PropTypes.string // status
    ]),
    onClick: PropTypes.func
  })).isRequired,
  total: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.node
  ]),
  units: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.shape({
      prefix: PropTypes.string,
      suffix: PropTypes.string
    })
  ])
};
<commit_msg>Add a responsive property to Legend, passed down to its ListItems (#1178)<commit_after>// (C) Copyright 2014-2016 Hewlett Packard Enterprise Development LP

import React, { Component, PropTypes } from 'react';
import classnames from 'classnames';
import FormattedMessage from './FormattedMessage';
import List from './List';
import ListItem from './ListItem';
import CSSClassnames from '../utils/CSSClassnames';
import Announcer from '../utils/Announcer';

const CLASS_ROOT = CSSClassnames.LEGEND;
const COLOR_INDEX = CSSClassnames.COLOR_INDEX;

function getMaxDecimalDigits(series) {
  let maxDigits = 0;
  series.forEach((item) => {
    const currentDigitsGroup = /\.(\d*)$/.exec(item.value.toString());
    if (currentDigitsGroup) {
      const currentDigits = currentDigitsGroup[1].length;
      maxDigits = Math.max(maxDigits, currentDigits);
    }
  });

  return Math.pow(10, maxDigits);
}

export default class Legend extends Component {

  constructor(props, context) {
    super(props, context);

    this._onActive = this._onActive.bind(this);
    this._renderSeries = this._renderSeries.bind(this);
    this._renderSwatch = this._renderSwatch.bind(this);
    this._renderLabel = this._renderLabel.bind(this);
    this._renderValue = this._renderValue.bind(this);
    this._renderTotal = this._renderTotal.bind(this);
    this._seriesTotal = this._seriesTotal.bind(this);

    this.state = {activeIndex: this.props.activeIndex};
  }

  componentWillReceiveProps (newProps) {
    if (newProps.activeIndex !== this.state.activeIndex) {
      this.setState({activeIndex: newProps.activeIndex});
    }
  }

  componentDidUpdate () {
    const { announce } = this.props;
    if (announce) {
      Announcer.announce(this.legendRef.textContent);
    }
  }

  _onActive (index) {
    const { onActive } = this.props;
    this.setState({activeIndex: index});
    if (onActive) {
      onActive(index);
    }
  }

  _itemColorIndex (item, index) {
    return item.colorIndex || `graph-${index + 1}`;
  }

  _renderSwatch (item, index) {
    const colorIndex = this._itemColorIndex(item, index);
    return (
      <svg className={
          `${CLASS_ROOT}__item-swatch ${COLOR_INDEX}-${colorIndex}`
        } viewBox="0 0 12 12">
        <path className={item.className} d="M 5 0 l 0 12" />
      </svg>
    );
  }

  _renderLabel (item, swatch) {
    if (swatch) {
      return (
        <span className={`${CLASS_ROOT}__item-label`}>
          {swatch}
          {item.label}

      );
    } else {
      return (
        <span className={`${CLASS_ROOT}__item-label`}>{item.label}
      );
    }
  }

  _renderValue (item) {
    const { units } = this.props;
    const unitsValue = item.units || units;
    const valueClasses = `${CLASS_ROOT}__item-value`;
    let unitsPrefix;
    let unitsSuffix;
    if (unitsValue) {
      if (unitsValue.prefix) {
        unitsPrefix = (
          <span className={`${CLASS_ROOT}__item-units`}>
            {unitsValue.prefix}

        );
      }
      if (unitsValue.suffix ||
        (typeof unitsValue === 'string' || unitsValue instanceof String)) {
        unitsSuffix = (
          <span className={`${CLASS_ROOT}__item-units`}>
            {unitsValue.suffix || unitsValue}

        );
      }
    }
    return (

        {unitsPrefix}
        {item.value}
        {unitsSuffix}

    );
  }

  _seriesTotal () {
    const { series } = this.props;
    const maxDecimalDigits = getMaxDecimalDigits(series);
    let total = 0;
    series.forEach(item =>
      total += (typeof item.value === 'number' ?
       item.value : 0) * maxDecimalDigits );
    return total / maxDecimalDigits;
  }

  _renderSeries () {
    const { series, responsive } = this.props;
    const { activeIndex } = this.state;

    return series.map((item, index) => {
      const legendClasses = classnames(
        `${CLASS_ROOT}__item`, {
          [`${CLASS_ROOT}__item--active`]: index === activeIndex,
          [`${CLASS_ROOT}__item--clickable`]: item.onClick
        }
      );

      let swatch;
      if (item.hasOwnProperty('colorIndex')) {
        swatch = this._renderSwatch(item, index);
      }

      let label;
      if (item.hasOwnProperty('label')) {
        label = this._renderLabel(item, swatch);
      }

      let value;
      if (item.hasOwnProperty('value')) {
        value = this._renderValue(item);
      }

      return (
        <ListItem onClick={item.onClick} justify='between'
          separator='none' pad={{ horizontal: 'small' }}
          key={item.label || index} className={legendClasses}
          onMouseOver={this._onActive.bind(this, index)}
          onMouseOut={this._onActive.bind(this, undefined)}
          responsive={responsive} >
          {label}
          {value}
        </ListItem>
      );
    }, this);
  }

  _renderTotal () {
    const { total, units, responsive } = this.props;
    let totalValue;
    if (total !== true) {
      totalValue = total;
    } else {
      totalValue = this._seriesTotal();
    }
    let unitsPrefix;
    let unitsSuffix;
    if (units && units.prefix) {
      unitsPrefix = (
        <span className={`${CLASS_ROOT}__total-units`}>
          {units.prefix}

      );
    }
    if (units &&
      (units.suffix ||
        (typeof units === 'string' ||
        units instanceof String))) {
      unitsSuffix = (
        <span className={`${CLASS_ROOT}__total-units`}>
          {units.suffix || units}

      );
    }

    return (
      <ListItem className={`${CLASS_ROOT}__total`}
        justify='between' separator='none' pad={{ horizontal: 'small' }}
        responsive={responsive} >
        <span className={`${CLASS_ROOT}__total-label`}>
          <FormattedMessage id="Total" defaultMessage="Total" />

        <span className={`${CLASS_ROOT}__total-value`}>
          {unitsPrefix}
          {totalValue}
          {unitsSuffix}

      </ListItem>
    );
  }

  render () {
    const { className, series, total, ...props } = this.props;
    delete props.activeIndex;
    delete props.announce;
    delete props.onActive;
    delete props.units;
    delete props.responsive;

    const classes = classnames(
      CLASS_ROOT,
      className
    );

    let items = this._renderSeries();

    // build legend from bottom to top, to align with Meter bar stacking
    items.reverse();

    let totalNode;
    if (total && series.length > 1) {
      totalNode = this._renderTotal();
    }

    return (
      <List ref={ref => this.legendRef = ref} {...props} className={classes}>
        {items.reverse()}
        {totalNode}
      </List>
    );
  }

}

Legend.defaultProps = {
  announce: false
};

Legend.propTypes = {
  activeIndex: PropTypes.number,
  announce: PropTypes.bool,
  onActive: PropTypes.func,
  series: PropTypes.arrayOf(PropTypes.shape({
    label: PropTypes.string,
    value: PropTypes.oneOfType([
      PropTypes.number,
      PropTypes.node
    ]),
    units: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.shape({
        prefix: PropTypes.string,
        suffix: PropTypes.string
      })
    ]),
    colorIndex: PropTypes.oneOfType([
      PropTypes.number, // 1-6
      PropTypes.string // status
    ]),
    onClick: PropTypes.func
  })).isRequired,
  total: PropTypes.oneOfType([
    PropTypes.bool,
    PropTypes.node
  ]),
  units: PropTypes.oneOfType([
    PropTypes.string,
    PropTypes.shape({
      prefix: PropTypes.string,
      suffix: PropTypes.string
    })
  ]),
  responsive: PropTypes.bool
};
<|endoftext|>


<commit_before>module.exports = (config) => {
    const options = {
        reporters: ["progress", "coverage"],
        frameworks: ["mocha"],
        files: [
            {pattern: require.resolve("chai/chai"), watched: false},
            {pattern: require.resolve("vue/dist/vue"), watched: false},
            {pattern: require.resolve("js-polyfills/typedarray.js"), watched: false},
            {pattern: require.resolve("three"), watched: false},
            {pattern: "test/index.js", watched: false},
            {pattern: "test/**/*.spec.js"},
            {pattern: require.resolve("three/examples/fonts/helvetiker_regular.typeface.json"), included: false, watched: false},
            {pattern: require.resolve("three/examples/fonts/helvetiker_bold.typeface.json"), included: false, watched: false},
            {pattern: "test/sample_texture.png", included: false, watched: false}
        ],
        preprocessors: {
            "test/index.js": ["rollup"],
            "test/**/*.spec.js": ["babel"]
        },
        client: {
            mocha: {
                timeout: 10000
            }
        },
        rollupPreprocessor: {
            format: "iife",
            name: "VueGL",
            external: "three",
            globals: {
                three: "THREE"
            },
            plugins: [
                require("rollup-plugin-istanbul")({include: "src/**"}),
                require("rollup-plugin-babel")()
            ],
            sourcemap: "inline"
        },
        coverageReporter: {
            type: "text-summary",
        }
    };

    if (process.env.CI) {
        options.reporters= ["saucelabs", "coverage", "junit"];
        options.junitReporter = {outputDir: "junit"};
        options.coverageReporter = {type: "lcovonly", dir: "coverage"};
        options.browserNoActivityTimeout = 30000;
        options.browserDisconnectTolerance = 2;
        options.sauceLabs = {
            testName: "VueGL unit test",
            recordScreenshots: false,
            public: "public restricted"
        };
        options.customLaunchers = {
            "Chrome 26 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "chrome",
                version: "26"
            },
            "Chrome (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "chrome",
                version: "latest"
            },
            "Internet Explorer 9 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "internet explorer",
                version: "9"
            },
            "Internet Explorer (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "internet explorer",
                version: "latest"
            },
            "Firefox 4 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "firefox",
                version: "4"
            },
            "Firefox (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "firefox",
                version: "latest"
            },
            "Edge 13 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "MicrosoftEdge",
                version: "13"
            },
            "Edge (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "MicrosoftEdge",
                version: "latest"
            },
            "Chrome 26 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "chrome",
                version: "26"
            },
            "Chrome (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "chrome",
                version: "latest"
            },
            "Firefox 4 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "firefox",
                version: "4"
            },
            "Firefox (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "firefox",
                version: "latest"
            },
            "Internet Explorer (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "internet explorer",
                version: "latest"
            },
            "Safari (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "safari",
                version: "latest"
            },
            "Chrome (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "chrome",
                version: "latest"
            },
            "Chrome 27 on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "chrome",
                version: "27"
            },
            "Firefox (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "firefox",
                version: "latest"
            },
            "Firefox 4 on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "firefox",
                version: "4"
            },
            "Safari 9 on Mac OS X El Capitan": {
                base: "SauceLabs",
                platform: "OS X 10.11",
                browserName: "safari",
                version: "9"
            },
            "Safari 8 on Mac OS X Yosemite": {
                base: "SauceLabs",
                platform: "OS X 10.10",
                browserName: "safari",
                version: "8"
            },
            "Safari 7 on Mac OS X Mavericks": {
                base: "SauceLabs",
                platform: "OS X 10.9",
                browserName: "safari",
                version: "7"
            }
        };
        options.browsers = Object.keys(options.customLaunchers);
        options.singleRun = true;
        options.concurrency = 4;
    }

    config.set(options);
};
<commit_msg>Add the dots reporter to output console on CI.<commit_after>module.exports = (config) => {
    const options = {
        reporters: ["progress", "coverage"],
        frameworks: ["mocha"],
        files: [
            {pattern: require.resolve("chai/chai"), watched: false},
            {pattern: require.resolve("vue/dist/vue"), watched: false},
            {pattern: require.resolve("js-polyfills/typedarray.js"), watched: false},
            {pattern: require.resolve("three"), watched: false},
            {pattern: "test/index.js", watched: false},
            {pattern: "test/**/*.spec.js"},
            {pattern: require.resolve("three/examples/fonts/helvetiker_regular.typeface.json"), included: false, watched: false},
            {pattern: require.resolve("three/examples/fonts/helvetiker_bold.typeface.json"), included: false, watched: false},
            {pattern: "test/sample_texture.png", included: false, watched: false}
        ],
        preprocessors: {
            "test/index.js": ["rollup"],
            "test/**/*.spec.js": ["babel"]
        },
        client: {
            mocha: {
                timeout: 10000
            }
        },
        rollupPreprocessor: {
            format: "iife",
            name: "VueGL",
            external: "three",
            globals: {
                three: "THREE"
            },
            plugins: [
                require("rollup-plugin-istanbul")({include: "src/**"}),
                require("rollup-plugin-babel")()
            ],
            sourcemap: "inline"
        },
        coverageReporter: {
            type: "text-summary",
        }
    };

    if (process.env.CI) {
        options.reporters= ["saucelabs", "coverage", "junit", "dots"];
        options.junitReporter = {outputDir: "junit"};
        options.coverageReporter = {type: "lcovonly", dir: "coverage"};
        options.browserNoActivityTimeout = 30000;
        options.browserDisconnectTolerance = 2;
        options.sauceLabs = {
            testName: "VueGL unit test",
            recordScreenshots: false,
            public: "public restricted"
        };
        options.customLaunchers = {
            "Chrome 26 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "chrome",
                version: "26"
            },
            "Chrome (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "chrome",
                version: "latest"
            },
            "Internet Explorer 9 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "internet explorer",
                version: "9"
            },
            "Internet Explorer (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "internet explorer",
                version: "latest"
            },
            "Firefox 4 on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "firefox",
                version: "4"
            },
            "Firefox (latest) on Windows 7": {
                base: "SauceLabs",
                platform: "Windows 7",
                browserName: "firefox",
                version: "latest"
            },
            "Edge 13 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "MicrosoftEdge",
                version: "13"
            },
            "Edge (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "MicrosoftEdge",
                version: "latest"
            },
            "Chrome 26 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "chrome",
                version: "26"
            },
            "Chrome (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "chrome",
                version: "latest"
            },
            "Firefox 4 on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "firefox",
                version: "4"
            },
            "Firefox (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "firefox",
                version: "latest"
            },
            "Internet Explorer (latest) on Windows 10": {
                base: "SauceLabs",
                platform: "Windows 10",
                browserName: "internet explorer",
                version: "latest"
            },
            "Safari (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "safari",
                version: "latest"
            },
            "Chrome (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "chrome",
                version: "latest"
            },
            "Chrome 27 on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "chrome",
                version: "27"
            },
            "Firefox (latest) on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "firefox",
                version: "latest"
            },
            "Firefox 4 on Mac OS X Sierra": {
                base: "SauceLabs",
                platform: "macOS 10.12",
                browserName: "firefox",
                version: "4"
            },
            "Safari 9 on Mac OS X El Capitan": {
                base: "SauceLabs",
                platform: "OS X 10.11",
                browserName: "safari",
                version: "9"
            },
            "Safari 8 on Mac OS X Yosemite": {
                base: "SauceLabs",
                platform: "OS X 10.10",
                browserName: "safari",
                version: "8"
            },
            "Safari 7 on Mac OS X Mavericks": {
                base: "SauceLabs",
                platform: "OS X 10.9",
                browserName: "safari",
                version: "7"
            }
        };
        options.browsers = Object.keys(options.customLaunchers);
        options.singleRun = true;
        options.concurrency = 4;
    }

    config.set(options);
};
<|endoftext|>


<commit_before>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

import type {RequestParameters} from '../util/RelayConcreteNode';
import type {
  CacheConfig,
  Disposable,
  Variables,
} from '../util/RelayRuntimeTypes';
import type RelayObservable, {ObservableFromValue} from './RelayObservable';

/**
 * An interface for fetching the data for one or more (possibly interdependent)
 * queries.
 */
export type Network = {|
  execute: ExecuteFunction,
|};

export type PayloadData = {[key: string]: mixed};

export type PayloadError = {
  message: string,
  locations?: Array<{
    line: number,
    column: number,
  }>,
  severity?: 'CRITICAL' | 'ERROR' | 'WARNING', // Not officially part of the spec, but used at Facebook
};

export type PayloadExtensions = {[key: string]: mixed};

/**
 * The shape of a GraphQL response as dictated by the
 * [spec](http://facebook.github.io/graphql/#sec-Response)
 */
export type GraphQLResponseWithData = {
  +data: PayloadData,
  +errors?: Array<PayloadError>,
  +extensions?: PayloadExtensions,
  +label?: string,
  +path?: Array<string | number>,
};
export type GraphQLResponseWithoutData = {
  +data?: ?PayloadData,
  +errors: Array<PayloadError>,
  +extensions?: PayloadExtensions,
  +label?: string,
  +path?: Array<string | number>,
};
export type GraphQLResponse =
  | GraphQLResponseWithData
  | GraphQLResponseWithoutData;

/**
 * A function that returns an Observable representing the response of executing
 * a GraphQL operation.
 */
export type ExecuteFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  uploadables?: ?UploadableMap,
) => RelayObservable<GraphQLResponse>;

/**
 * A function that executes a GraphQL operation with request/response semantics.
 *
 * May return an Observable or Promise of a plain GraphQL server response, or
 * a composed ExecutePayload object supporting additional metadata.
 */
export type FetchFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  uploadables: ?UploadableMap,
) => ObservableFromValue<GraphQLResponse>;

/**
 * A function that executes a GraphQL subscription operation, returning one or
 * more raw server responses over time.
 *
 * May return an Observable, otherwise must call the callbacks found in the
 * fourth parameter.
 */
export type SubscribeFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  observer?: LegacyObserver<GraphQLResponse>,
) => RelayObservable<GraphQLResponse> | Disposable;

// $FlowFixMe(site=react_native_fb) this is compatible with classic api see D4658012
export type Uploadable = File | Blob;
export type UploadableMap = {[key: string]: Uploadable};

// Supports legacy SubscribeFunction definitions. Do not use in new code.
export type LegacyObserver<-T> = {|
  +onCompleted?: ?() => void,
  +onError?: ?(error: Error) => void,
  +onNext?: ?(data: T) => void,
|};
<commit_msg>Fix www divergence<commit_after>/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict-local
 * @format
 */

'use strict';

import type {RequestParameters} from '../util/RelayConcreteNode';
import type {
  CacheConfig,
  Disposable,
  Variables,
} from '../util/RelayRuntimeTypes';
import type RelayObservable, {ObservableFromValue} from './RelayObservable';

/**
 * An interface for fetching the data for one or more (possibly interdependent)
 * queries.
 */
export type Network = {|
  execute: ExecuteFunction,
|};

export type PayloadData = {[key: string]: mixed};

export type PayloadError = {
  message: string,
  locations?: Array<{
    line: number,
    column: number,
  }>,
  severity?: 'CRITICAL' | 'ERROR' | 'WARNING', // Not officially part of the spec, but used at Facebook
};

export type PayloadExtensions = {[key: string]: mixed};

/**
 * The shape of a GraphQL response as dictated by the
 * [spec](http://facebook.github.io/graphql/#sec-Response)
 */
export type GraphQLResponseWithData = {
  +data: PayloadData,
  +errors?: Array<PayloadError>,
  +extensions?: PayloadExtensions,
  +label?: string,
  +path?: Array<string | number>,
};
export type GraphQLResponseWithoutData = {
  +data?: ?PayloadData,
  +errors: Array<PayloadError>,
  +extensions?: PayloadExtensions,
  +label?: string,
  +path?: Array<string | number>,
};
export type GraphQLResponse =
  | GraphQLResponseWithData
  | GraphQLResponseWithoutData;

/**
 * A function that returns an Observable representing the response of executing
 * a GraphQL operation.
 */
export type ExecuteFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  uploadables?: ?UploadableMap,
) => RelayObservable<GraphQLResponse>;

/**
 * A function that executes a GraphQL operation with request/response semantics.
 *
 * May return an Observable or Promise of a plain GraphQL server response, or
 * a composed ExecutePayload object supporting additional metadata.
 */
export type FetchFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  uploadables: ?UploadableMap,
) => ObservableFromValue<GraphQLResponse>;

/**
 * A function that executes a GraphQL subscription operation, returning one or
 * more raw server responses over time.
 *
 * May return an Observable, otherwise must call the callbacks found in the
 * fourth parameter.
 */
export type SubscribeFunction = (
  request: RequestParameters,
  variables: Variables,
  cacheConfig: CacheConfig,
  observer?: LegacyObserver<GraphQLResponse>,
) => RelayObservable<GraphQLResponse> | Disposable;

// $FlowFixMe(site=react_native_fb) this is compatible with classic api see D4658012
export type Uploadable = File | Blob;
// $FlowFixMe(site=mobile,www)
export type UploadableMap = {[key: string]: Uploadable};

// Supports legacy SubscribeFunction definitions. Do not use in new code.
export type LegacyObserver<-T> = {|
  +onCompleted?: ?() => void,
  +onError?: ?(error: Error) => void,
  +onNext?: ?(data: T) => void,
|};
<|endoftext|>


<commit_before>frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
	can_write() {
		// should be always true in case of button
		return true;
	},
	make_input: function() {
		var me = this;
		const btn_type = this.df.primary ? 'btn-primary': 'btn-default';
		this.$input = $(`<button class="btn btn-xs ${btn_type}">`)
			.prependTo(me.input_area)
			.on("click", function() {
				me.onclick();
			});
		this.input = this.$input.get(0);
		this.set_input_attributes();
		this.has_input = true;
		this.toggle_label(false);
	},
	onclick: function() {
		if (this.frm && this.frm.doc) {
			if (this.frm.script_manager.has_handlers(this.df.fieldname, this.doctype)) {
				this.frm.script_manager.trigger(this.df.fieldname, this.doctype, this.docname);
			} else {
				if (this.df.options) {
					this.run_server_script();
				}
			}
		} else if (this.df.click) {
			this.df.click();
		}
	},
	run_server_script: function() {
		// DEPRECATE
		var me = this;
		if(this.frm && this.frm.docname) {
			frappe.call({
				method: "run_doc_method",
				args: {'docs': this.frm.doc, 'method': this.df.options },
				btn: this.$input,
				callback: function(r) {
					if(!r.exc) {
						me.frm.refresh_fields();
					}
				}
			});
		}
	},
	hide() {
		this.$input.hide();
	},
	set_input_areas: function() {
		this._super();
		$(this.disp_area).removeClass().addClass("hide");
	},
	set_empty_description: function() {
		this.$wrapper.find(".help-box").empty().toggle(false);
	},
	set_label: function(label) {
		if (label) {
			this.df.label = label;
		}
		label = (this.df.icon ? frappe.utils.icon(this.df.icon) : "") + __(this.df.label);
		$(this.label_span).html(" ");
		this.$input && this.$input.html(label);
	}
});
<commit_msg>feat: allow button of different sizes in df<commit_after>frappe.ui.form.ControlButton = frappe.ui.form.ControlData.extend({
	can_write() {
		// should be always true in case of button
		return true;
	},
	make_input: function() {
		var me = this;
		const btn_type = this.df.primary ? 'btn-primary': 'btn-default';
		const btn_size = this.df.btn_size
			? `btn-${this.df.btn_size}`
			: "btn-xs";
		this.$input = $(`<button class="btn ${btn_size} ${btn_type}">`)
			.prependTo(me.input_area)
			.on("click", function() {
				me.onclick();
			});
		this.input = this.$input.get(0);
		this.set_input_attributes();
		this.has_input = true;
		this.toggle_label(false);
	},
	onclick: function() {
		if (this.frm && this.frm.doc) {
			if (this.frm.script_manager.has_handlers(this.df.fieldname, this.doctype)) {
				this.frm.script_manager.trigger(this.df.fieldname, this.doctype, this.docname);
			} else {
				if (this.df.options) {
					this.run_server_script();
				}
			}
		} else if (this.df.click) {
			this.df.click();
		}
	},
	run_server_script: function() {
		// DEPRECATE
		var me = this;
		if(this.frm && this.frm.docname) {
			frappe.call({
				method: "run_doc_method",
				args: {'docs': this.frm.doc, 'method': this.df.options },
				btn: this.$input,
				callback: function(r) {
					if(!r.exc) {
						me.frm.refresh_fields();
					}
				}
			});
		}
	},
	hide() {
		this.$input.hide();
	},
	set_input_areas: function() {
		this._super();
		$(this.disp_area).removeClass().addClass("hide");
	},
	set_empty_description: function() {
		this.$wrapper.find(".help-box").empty().toggle(false);
	},
	set_label: function(label) {
		if (label) {
			this.df.label = label;
		}
		label = (this.df.icon ? frappe.utils.icon(this.df.icon) : "") + __(this.df.label);
		$(this.label_span).html(" ");
		this.$input && this.$input.html(label);
	}
});
<|endoftext|>


<commit_before>module.exports = start;

function start(config){
    var app = config.app;

    app.get('/signPage', function(req, res){
        res.sendFile(config.directory + '/signPage/index.html');
    });

    app.get('/signPage/signIn', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    app.get('/signPage/signUP', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    app.get('/signPage/logOut', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    return (new test());
};

function test(){
    this.a = '23';
}

test.prototype.hehe = function(){
    console.log('asdf');
}
<commit_msg>update sign_module<commit_after>module.exports = start;

function start(config){
    var app = config.app;

    app.get('/signPage', function(req, res){
        res.sendFile(config.directory + '/signPage/index.html');
    });

    app.get('/signPage/signIn', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    app.get('/signPage/signUP', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    app.get('/signPage/logOut', function(req, res){
        res.sendFile(config.directory + '/index.html');
    });

    return (new test());
};

function signIn(){

}

function signUp(){

}
function logOut(){

}

function API(){
    this.a = '23';
}

API.prototype.hehe = function(){
    console.log('asdf');
}
<|endoftext|>


<commit_before>import {join} from 'path';
import fs from 'fs-extra';
import test from 'ava';
import fn from './../src';

const resolvedPath = join(__dirname, 'data-test');
const oldestFile = join(resolvedPath, 'oldest-modified-late.txt');
const latestFolder = join(resolvedPath, 'latest');

const wait = millisec => new Promise(resolve => setTimeout(() => resolve(), millisec));

const preTest = async () => {
	fs.ensureDirSync(resolvedPath);
	fs.ensureFileSync(oldestFile);
	const timeout1 = await wait(2000);
	clearTimeout(timeout1);
	fs.ensureDirSync(latestFolder);
	const timeout2 = await wait(2000);
	clearTimeout(timeout2);
	fs.writeFileSync(oldestFile, 'test2');
};

test.before(async () => {
	return await preTest();
});

test('get latest without type (fallback modified)', async t => {
	const res = await fn.latest(resolvedPath);
	t.is(res.file, 'oldest-modified-late.txt');
});

test('get latest with type specified', async t => {
	const res = await fn.latest(resolvedPath, 'birthtime');
	t.is(res.file, 'latest');
});

test('get oldest without type specified (fallback modified)', async t => {
	const res = await fn.oldest(resolvedPath);

	t.is(res.file, 'latest');
});

test('get oldest with type specified', async t => {
	const res = await fn.oldest(resolvedPath, 'birthtime');
	t.is(res.file, 'oldest-modified-late.txt');
});

test.after(() => {
	fs.removeSync(resolvedPath);
});
<commit_msg>trying to fix travis errors<commit_after>import {join} from 'path';
import fs from 'fs-extra';
import test from 'ava';
import fn from './../src';

const resolvedPath = join(__dirname, 'data-test');
const oldestFile = join(resolvedPath, 'oldest-modified-late.txt');
const latestFolder = join(resolvedPath, 'latest');

const wait = millisec => new Promise(resolve => setTimeout(() => resolve(), millisec));

const preTest = async () => {
	fs.ensureDirSync(resolvedPath);
	fs.ensureFileSync(oldestFile);
	const timeout1 = await wait(2000);
	console.log('Created file');
	clearTimeout(timeout1);
	fs.ensureDirSync(latestFolder);
	const timeout2 = await wait(2000);
	clearTimeout(timeout2);
	console.log('Created folder');
	const timeout3 = await wait(2000);
	clearTimeout(timeout3);
	fs.writeFileSync(oldestFile, 'test2');
	console.log('Modified file');
};

test.before(async () => {
	return await preTest();
});

test('get latest without type (fallback modified)', async t => {
	const res = await fn.latest(resolvedPath);
	t.is(res.file, 'oldest-modified-late.txt');
});

test('get latest with type specified', async t => {
	const res = await fn.latest(resolvedPath, 'birthtime');
	t.is(res.file, 'latest');
});

test('get oldest without type specified (fallback modified)', async t => {
	const res = await fn.oldest(resolvedPath);
	t.is(res.file, 'latest');
});

test('get oldest with type specified', async t => {
	const res = await fn.oldest(resolvedPath, 'birthtime');
	t.is(res.file, 'oldest-modified-late.txt');
});

test.after(() => {
	fs.removeSync(resolvedPath);
});
<|endoftext|>


<commit_before>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
 * The ContainerFactory is responsible for manage playback bootstrap and create containers.
 */

import BaseObject from 'base/base_object'
import Events from 'base/events'
import Container from 'components/container'
import $ from 'clappr-zepto'

import find from 'lodash.find'
import isPlainObject from 'lodash.isplainobject'

export default class ContainerFactory extends BaseObject {
  constructor(options, loader, i18n) {
    super(options)
    this._i18n = i18n
    this.loader = loader
  }

  createContainers() {
    return $.Deferred((promise) => {
      promise.resolve(this.options.sources.map((source) => {
        return this.createContainer(source)
      }))
    })
  }

  findPlaybackPlugin(source, mimeType) {
    return find(this.loader.playbackPlugins, (p) => { return p.canPlay(source, mimeType) })
  }

  createContainer(source) {
    var resolvedSource = null
    var mimeType = this.options.mimeType
    if (isPlainObject(source)) {
      resolvedSource = source.source.toString()
      if (source.mimeType) {
        mimeType = source.mimeType
      }
    } else {
      resolvedSource = source.toString()
    }

    if (resolvedSource.match(/^\/\//)) resolvedSource = window.location.protocol + resolvedSource

    var options = $.extend({}, this.options, {
      src: resolvedSource,
      mimeType: mimeType
    })
    var playbackPlugin = this.findPlaybackPlugin(resolvedSource, mimeType)
    var playback = new playbackPlugin(options, this._i18n)

    options = $.extend({}, options, {playback: playback})

    var container = new Container(options, this._i18n)
    var defer = $.Deferred()
    defer.promise(container)
    this.addContainerPlugins(container)
    this.listenToOnce(container, Events.CONTAINER_READY, () => defer.resolve(container))
    return container
  }

  addContainerPlugins(container) {
    this.loader.containerPlugins.forEach((Plugin) => {
      container.addPlugin(new Plugin(container))
    })
  }
}
<commit_msg>container factory: override options property to allow it to be set externally (fixes #1072)<commit_after>// Copyright 2014 Globo.com Player authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

/**
 * The ContainerFactory is responsible for manage playback bootstrap and create containers.
 */

import BaseObject from 'base/base_object'
import Events from 'base/events'
import Container from 'components/container'
import $ from 'clappr-zepto'

import find from 'lodash.find'
import isPlainObject from 'lodash.isplainobject'

export default class ContainerFactory extends BaseObject {
  get options() { return this._options }
  set options(options) { this._options = options }

  constructor(options, loader, i18n) {
    super(options)
    this._i18n = i18n
    this.loader = loader
  }

  createContainers() {
    return $.Deferred((promise) => {
      promise.resolve(this.options.sources.map((source) => {
        return this.createContainer(source)
      }))
    })
  }

  findPlaybackPlugin(source, mimeType) {
    return find(this.loader.playbackPlugins, (p) => { return p.canPlay(source, mimeType) })
  }

  createContainer(source) {
    var resolvedSource = null
    var mimeType = this.options.mimeType
    if (isPlainObject(source)) {
      resolvedSource = source.source.toString()
      if (source.mimeType) {
        mimeType = source.mimeType
      }
    } else {
      resolvedSource = source.toString()
    }

    if (resolvedSource.match(/^\/\//)) resolvedSource = window.location.protocol + resolvedSource

    var options = $.extend({}, this.options, {
      src: resolvedSource,
      mimeType: mimeType
    })
    var playbackPlugin = this.findPlaybackPlugin(resolvedSource, mimeType)
    var playback = new playbackPlugin(options, this._i18n)

    options = $.extend({}, options, {playback: playback})

    var container = new Container(options, this._i18n)
    var defer = $.Deferred()
    defer.promise(container)
    this.addContainerPlugins(container)
    this.listenToOnce(container, Events.CONTAINER_READY, () => defer.resolve(container))
    return container
  }

  addContainerPlugins(container) {
    this.loader.containerPlugins.forEach((Plugin) => {
      container.addPlugin(new Plugin(container))
    })
  }
}
<|endoftext|>


<commit_before>/*global require, exports, console, setInterval, clearInterval*/

var logger = require('./../common/logger').logger;

// Logger
var log = logger.getLogger("RoomController");

exports.RoomController = function (spec) {
    "use strict";

    var that = {},
        // {id: array of subscribers}
        subscribers = {},
        // {id: erizoJS_id}
        publishers = {},
        // {erizoJS_id: {publishers: [ids], ka_count: count}}
        erizos = {},

        // {id: ExternalOutput}
        externalOutputs = {};

    var amqper = spec.amqper;
    var ecch = spec.ecch;

    var KEEPALIVE_INTERVAL = 5*1000;
    var TIMEOUT_LIMIT = 2;
    var MAX_ERIZOJS_RETRIES = 2;

    var eventListeners = [];

    var callbackFor = function(erizo_id) {

        return function(ok) {
            if (!erizos[erizo_id]) return;

            if (ok !== true) {
                erizos[erizo_id].ka_count ++;

                if (erizos[erizo_id].ka_count > TIMEOUT_LIMIT) {

                    for (var p in erizos[erizo_id].publishers) {
                        log.error("Lost connection with ErizoJS, will remove publishers", erizo_id);
                        dispatchEvent("unpublish", erizos[erizo_id].publishers[p]);
                    }
                    ecch.deleteErizoJS(erizo_id);
                    delete erizos[erizo_id];
                }
            } else {
                erizos[erizo_id].ka_count = 0;
            }
        }
    };

    var sendKeepAlive = function() {
        for (var e in erizos) {
            amqper.callRpc("ErizoJS_" + e, "keepAlive", [], {callback: callbackFor(e)});
        }
    };

    var keepAliveLoop = setInterval(sendKeepAlive, KEEPALIVE_INTERVAL);

    var getErizoJS = function(callback) {
    	ecch.getErizoJS(function(erizo_id) {
            if (!erizos[erizo_id] && erizo_id !== 'timeout') {
                erizos[erizo_id] = {publishers: [], ka_count: 0};
            }
            callback(erizo_id);
        });
    };

    var getErizoQueue = function(publisher_id) {
        return "ErizoJS_" + publishers[publisher_id];
    };

    var dispatchEvent = function(type, event) {
        for (var event_id in eventListeners) {
            eventListeners[event_id](type, event);
        }

    };

    that.addEventListener = function(eventListener) {
        eventListeners.push(eventListener);
    };

    that.addExternalInput = function (publisher_id, url, callback) {

        if (publishers[publisher_id] === undefined) {

            log.info("Adding external input peer_id ", publisher_id);

            getErizoJS(function(erizo_id) {
                // then we call its addPublisher method.
    	        var args = [publisher_id, url];

                // Track publisher locally
                publishers[publisher_id] = erizo_id;
                subscribers[publisher_id] = [];

                amqper.callRpc(getErizoQueue(publisher_id), "addExternalInput", args, {callback: callback});

                erizos[erizo_id].publishers.push(publisher_id);

            });
        } else {
            log.info("Publisher already set for", publisher_id);
        }
    };

    that.addExternalOutput = function (publisher_id, url, callback) {
        if (publishers[publisher_id] !== undefined) {
            log.info("Adding ExternalOutput to " + publisher_id + " url " + url);

            var args = [publisher_id, url];

            amqper.callRpc(getErizoQueue(publisher_id), "addExternalOutput", args, undefined);

            // Track external outputs
            externalOutputs[url] = publisher_id;

            callback('success');
        } else {
            callback('error');
        }

    };

    that.removeExternalOutput = function (url, callback) {
        var publisher_id = externalOutputs[url];

        if (publisher_id !== undefined && publishers[publisher_id] != undefined) {
            log.info("Stopping ExternalOutput: url " + url);

            var args = [publisher_id, url];
            amqper.callRpc(getErizoQueue(publisher_id), "removeExternalOutput", args, undefined);

            // Remove track
            delete externalOutputs[url];
            callback(true);
        } else {
            callback(null, 'This stream is not being recorded');
        }
    };

    that.processSignaling = function (streamId, peerId, msg) {

        if (publishers[streamId] !== undefined) {

//            log.info("Sending signaling mess to erizoJS of st ", streamId, ' of peer ', peerId);

            var args = [streamId, peerId, msg];
            amqper.callRpc(getErizoQueue(streamId), "processSignaling", args, {});

        }
    };

    /*
     * Adds a publisher to the room. This creates a new OneToManyProcessor
     * and a new WebRtcConnection. This WebRtcConnection will be the publisher
     * of the OneToManyProcessor.
     */
    that.addPublisher = function (publisher_id, options, callback, retries) {
        if (retries === undefined)
            retries = 0;

        if (publishers[publisher_id] === undefined) {

            log.info("Adding publisher peer_id ", publisher_id, "options", options);;

            // We create a new ErizoJS with the publisher_id.
            getErizoJS(function(erizo_id) {

                if (erizo_id === 'timeout') {
                    log.error("Cannot contact ErizoAgent to add Publisher -- timeout");
                    callback('timeout-agent');
                    return;
                }
            	log.debug("ErizoJS id:", erizo_id, "assigned for publisher", publisher_id);
                // Track publisher locally
                // then we call its addPublisher method.
                var args = [publisher_id, options];
                publishers[publisher_id] = erizo_id;
                subscribers[publisher_id] = [];

                amqper.callRpc(getErizoQueue(publisher_id), "addPublisher", args, {callback: function (data){
                    if (data === 'timeout'){
                        if (retries < MAX_ERIZOJS_RETRIES){
                            publishers[publisher_id] = undefined;
                            retries++;
                            log.warn("ErizoJS timed out, trying again to publish", publisher_id, "number of tries", retries);
                            that.addPublisher(publisher_id, options,callback, retries);
                            return;
                        }
                        log.error("Can not contact ErizoJS", publisher_id , " failed add Publisher -- timeout");
                        var index = erizos[publishers[publisher_id]].publishers.indexOf(publisher_id);
                        erizos[publishers[publisher_id]].publishers.splice(index, 1);
                        callback('timeout-erizojs');
                        return;
                    }else{
                        callback(data);
                    }
                }});

                erizos[erizo_id].publishers.push(publisher_id);
            });

        } else {
            log.warn("Publisher already set for", publisher_id);
        }
    };

    /*
     * Adds a subscriber to the room. This creates a new WebRtcConnection.
     * This WebRtcConnection will be added to the subscribers list of the
     * OneToManyProcessor.
     */
    that.addSubscriber = function (subscriber_id, publisher_id, options, callback, retries) {
        if (subscriber_id === null){
          callback("Error: null subscriber_id");
          return;
        }
        if (retries === undefined)
            retries = 0;

        if (publishers[publisher_id] !== undefined && subscribers[publisher_id].indexOf(subscriber_id) === -1) {
            log.info("Adding subscriber ", subscriber_id, ' to publisher ', publisher_id, "options", options);

            if (options.audio === undefined) options.audio = true;
            if (options.video === undefined) options.video = true;

            var args = [subscriber_id, publisher_id, options];
            //TODO: Potential problem here if erizoJS is not reachable
            amqper.callRpc(getErizoQueue(publisher_id, undefined), "addSubscriber", args, {callback: function (data){
                if (data === 'timeout'){
                    if (retries < MAX_ERIZOJS_RETRIES){
                        retries++;
                        log.warn("ErizoJS timed out, trying again to subscribe to ", publisher_id, "from", subscriber_id, "number of tries", retries);
                        that.addSubscriber(subscriber_id, publisher_id, options, callback, retries);
                        return;
                    }
                    log.error("Can not contact to ErizoJS", publisher_id , " failed add Subscriber -- timeout");
                    callback('timeout');
                    return;
                }else if (data === 'initializing'){
                    subscribers[publisher_id].push(subscriber_id);
                }
                callback(data);
            }});
        }
    };

    /*
     * Removes a publisher from the room. This also deletes the associated OneToManyProcessor.
     */
    that.removePublisher = function (publisher_id) {

        if (subscribers[publisher_id] !== undefined && publishers[publisher_id]!== undefined) {
            log.info("Removing publisher", publisher_id);

            var args = [publisher_id];
            amqper.callRpc(getErizoQueue(publisher_id), "removePublisher", args, undefined);

            // Remove tracks
            var index = erizos[publishers[publisher_id]].publishers.indexOf(publisher_id);
            erizos[publishers[publisher_id]].publishers.splice(index, 1);

            delete subscribers[publisher_id];
            delete publishers[publisher_id];
            log.info('Removed muxer', publisher_id, ' muxers left ', Object.keys(publishers).length );
        }
    };

    /*
     * Removes a subscriber from the room. This also removes it from the associated OneToManyProcessor.
     */
    that.removeSubscriber = function (subscriber_id, publisher_id) {

        var index = subscribers[publisher_id].indexOf(subscriber_id);
        if (index !== -1) {
            log.info('Removing subscriber ', subscriber_id, 'to muxer ', publisher_id);

            var args = [subscriber_id, publisher_id];
            amqper.callRpc(getErizoQueue(publisher_id), "removeSubscriber", args, undefined);

            subscribers[publisher_id].splice(index, 1);
        }
    };

    /*
     * Removes all the subscribers related with a client.
     */
    that.removeSubscriptions = function (subscriber_id) {

        var publisher_id, index;

        log.info('Removing subscriptions of ', subscriber_id);

        for (publisher_id in subscribers) {
            if (subscribers.hasOwnProperty(publisher_id)) {
                index = subscribers[publisher_id].indexOf(subscriber_id);
                if (index !== -1) {
                    log.debug('Removing subscriber ', subscriber_id, 'from muxer ', publisher_id);

                    var args = [subscriber_id, publisher_id];
            		amqper.callRpc(getErizoQueue(publisher_id), "removeSubscriber", args, undefined);

            		// Remove tracks
                    subscribers[publisher_id].splice(index, 1);
                }
            }
        }
    };

    return that;
};
<commit_msg>Less retries for republish/resubscribe, logs include the erizoJS_id<commit_after>/*global require, exports, console, setInterval, clearInterval*/

var logger = require('./../common/logger').logger;

// Logger
var log = logger.getLogger("RoomController");

exports.RoomController = function (spec) {
    "use strict";

    var that = {},
        // {id: array of subscribers}
        subscribers = {},
        // {id: erizoJS_id}
        publishers = {},
        // {erizoJS_id: {publishers: [ids], ka_count: count}}
        erizos = {},

        // {id: ExternalOutput}
        externalOutputs = {};

    var amqper = spec.amqper;
    var ecch = spec.ecch;

    var KEEPALIVE_INTERVAL = 5*1000;
    var TIMEOUT_LIMIT = 2;
    var MAX_ERIZOJS_RETRIES = 1;

    var eventListeners = [];

    var callbackFor = function(erizo_id) {

        return function(ok) {
            if (!erizos[erizo_id]) return;

            if (ok !== true) {
                erizos[erizo_id].ka_count ++;

                if (erizos[erizo_id].ka_count > TIMEOUT_LIMIT) {

                    log.error("Lost connection with ErizoJS", erizo_id,"will remove publishers", erizos[erizo_id].publishers);
                    for (var p in erizos[erizo_id].publishers) {
                        dispatchEvent("unpublish", erizos[erizo_id].publishers[p]);
                    }
                    ecch.deleteErizoJS(erizo_id);
                    delete erizos[erizo_id];
                }
            } else {
                erizos[erizo_id].ka_count = 0;
            }
        }
    };

    var sendKeepAlive = function() {
        for (var e in erizos) {
            amqper.callRpc("ErizoJS_" + e, "keepAlive", [], {callback: callbackFor(e)});
        }
    };

    var keepAliveLoop = setInterval(sendKeepAlive, KEEPALIVE_INTERVAL);

    var getErizoJS = function(callback) {
    	ecch.getErizoJS(function(erizo_id) {
            if (!erizos[erizo_id] && erizo_id !== 'timeout') {
                erizos[erizo_id] = {publishers: [], ka_count: 0};
            }
            callback(erizo_id);
        });
    };

    var getErizoQueue = function(publisher_id) {
        return "ErizoJS_" + publishers[publisher_id];
    };

    var dispatchEvent = function(type, event) {
        for (var event_id in eventListeners) {
            eventListeners[event_id](type, event);
        }

    };

    that.addEventListener = function(eventListener) {
        eventListeners.push(eventListener);
    };

    that.addExternalInput = function (publisher_id, url, callback) {

        if (publishers[publisher_id] === undefined) {

            log.info("Adding external input peer_id ", publisher_id);

            getErizoJS(function(erizo_id) {
                // then we call its addPublisher method.
    	        var args = [publisher_id, url];

                // Track publisher locally
                publishers[publisher_id] = erizo_id;
                subscribers[publisher_id] = [];

                amqper.callRpc(getErizoQueue(publisher_id), "addExternalInput", args, {callback: callback});

                erizos[erizo_id].publishers.push(publisher_id);

            });
        } else {
            log.info("Publisher already set for", publisher_id);
        }
    };

    that.addExternalOutput = function (publisher_id, url, callback) {
        if (publishers[publisher_id] !== undefined) {
            log.info("Adding ExternalOutput to " + publisher_id + " url " + url);

            var args = [publisher_id, url];

            amqper.callRpc(getErizoQueue(publisher_id), "addExternalOutput", args, undefined);

            // Track external outputs
            externalOutputs[url] = publisher_id;

            callback('success');
        } else {
            callback('error');
        }

    };

    that.removeExternalOutput = function (url, callback) {
        var publisher_id = externalOutputs[url];

        if (publisher_id !== undefined && publishers[publisher_id] != undefined) {
            log.info("Stopping ExternalOutput: url " + url);

            var args = [publisher_id, url];
            amqper.callRpc(getErizoQueue(publisher_id), "removeExternalOutput", args, undefined);

            // Remove track
            delete externalOutputs[url];
            callback(true);
        } else {
            callback(null, 'This stream is not being recorded');
        }
    };

    that.processSignaling = function (streamId, peerId, msg) {

        if (publishers[streamId] !== undefined) {

//            log.info("Sending signaling mess to erizoJS of st ", streamId, ' of peer ', peerId);

            var args = [streamId, peerId, msg];
            amqper.callRpc(getErizoQueue(streamId), "processSignaling", args, {});

        }
    };

    /*
     * Adds a publisher to the room. This creates a new OneToManyProcessor
     * and a new WebRtcConnection. This WebRtcConnection will be the publisher
     * of the OneToManyProcessor.
     */
    that.addPublisher = function (publisher_id, options, callback, retries) {
        if (retries === undefined)
            retries = 0;

        if (publishers[publisher_id] === undefined) {

            log.info("Adding publisher peer_id ", publisher_id, "options", options);;

            // We create a new ErizoJS with the publisher_id.
            getErizoJS(function(erizo_id) {

                if (erizo_id === 'timeout') {
                    log.error("Cannot contact ErizoAgent to add Publisher -- timeout");
                    callback('timeout-agent');
                    return;
                }
            	log.debug("ErizoJS id:", erizo_id, "assigned for publisher", publisher_id);
                // Track publisher locally
                // then we call its addPublisher method.
                var args = [publisher_id, options];
                publishers[publisher_id] = erizo_id;
                subscribers[publisher_id] = [];

                amqper.callRpc(getErizoQueue(publisher_id), "addPublisher", args, {callback: function (data){
                    if (data === 'timeout'){
                        if (retries < MAX_ERIZOJS_RETRIES){
                            log.warn("ErizoJS timed out, trying again to publish", getErizoQueue(publisher_id), "number of tries", retries);
                            publishers[publisher_id] = undefined;
                            retries++;
                            that.addPublisher(publisher_id, options,callback, retries);
                            return;
                        }
                        log.error("Can not contact ErizoJS", getErizoQueue(publisher_id) , " failed add Publisher -- timeout");
                        var index = erizos[publishers[publisher_id]].publishers.indexOf(publisher_id);
                        erizos[publishers[publisher_id]].publishers.splice(index, 1);
                        callback('timeout-erizojs');
                        return;
                    }else{
                        callback(data);
                    }
                }});

                erizos[erizo_id].publishers.push(publisher_id);
            });

        } else {
            log.warn("Publisher already set for", publisher_id);
        }
    };

    /*
     * Adds a subscriber to the room. This creates a new WebRtcConnection.
     * This WebRtcConnection will be added to the subscribers list of the
     * OneToManyProcessor.
     */
    that.addSubscriber = function (subscriber_id, publisher_id, options, callback, retries) {
        if (subscriber_id === null){
          callback("Error: null subscriber_id");
          return;
        }
        if (retries === undefined)
            retries = 0;

        if (publishers[publisher_id] !== undefined && subscribers[publisher_id].indexOf(subscriber_id) === -1) {
            log.info("Adding subscriber ", subscriber_id, ' to publisher ', publisher_id, "options", options);

            if (options.audio === undefined) options.audio = true;
            if (options.video === undefined) options.video = true;

            var args = [subscriber_id, publisher_id, options];
            //TODO: Potential problem here if erizoJS is not reachable
            amqper.callRpc(getErizoQueue(publisher_id, undefined), "addSubscriber", args, {callback: function (data){
                if (data === 'timeout'){
                    if (retries < MAX_ERIZOJS_RETRIES){
                        retries++;
                        log.warn("ErizoJS timed out, trying again to subscribe to ", publisher_id, "in", getErizoQueue(publisher_id), "from", subscriber_id, "number of tries", retries);
                        that.addSubscriber(subscriber_id, publisher_id, options, callback, retries);
                        return;
                    }
                    log.error("Can not contact to ErizoJS", getErizoQueue(publisher_id) , " failed add Subscriber", subscriber_id," -- timeout");
                    callback('timeout');
                    return;
                }else if (data === 'initializing'){
                    subscribers[publisher_id].push(subscriber_id);
                }
                callback(data);
            }});
        }
    };

    /*
     * Removes a publisher from the room. This also deletes the associated OneToManyProcessor.
     */
    that.removePublisher = function (publisher_id) {

        if (subscribers[publisher_id] !== undefined && publishers[publisher_id]!== undefined) {
            log.info("Removing publisher", publisher_id);

            var args = [publisher_id];
            amqper.callRpc(getErizoQueue(publisher_id), "removePublisher", args, undefined);

            // Remove tracks
            var index = erizos[publishers[publisher_id]].publishers.indexOf(publisher_id);
            erizos[publishers[publisher_id]].publishers.splice(index, 1);

            delete subscribers[publisher_id];
            delete publishers[publisher_id];
            log.info('Removed muxer', publisher_id, ' muxers left ', Object.keys(publishers).length );
        }
    };

    /*
     * Removes a subscriber from the room. This also removes it from the associated OneToManyProcessor.
     */
    that.removeSubscriber = function (subscriber_id, publisher_id) {

        var index = subscribers[publisher_id].indexOf(subscriber_id);
        if (index !== -1) {
            log.info('Removing subscriber ', subscriber_id, 'to muxer ', publisher_id);

            var args = [subscriber_id, publisher_id];
            amqper.callRpc(getErizoQueue(publisher_id), "removeSubscriber", args, undefined);

            subscribers[publisher_id].splice(index, 1);
        }
    };

    /*
     * Removes all the subscribers related with a client.
     */
    that.removeSubscriptions = function (subscriber_id) {

        var publisher_id, index;

        log.info('Removing subscriptions of ', subscriber_id);

        for (publisher_id in subscribers) {
            if (subscribers.hasOwnProperty(publisher_id)) {
                index = subscribers[publisher_id].indexOf(subscriber_id);
                if (index !== -1) {
                    log.debug('Removing subscriber ', subscriber_id, 'from muxer ', publisher_id);

                    var args = [subscriber_id, publisher_id];
            		amqper.callRpc(getErizoQueue(publisher_id), "removeSubscriber", args, undefined);

            		// Remove tracks
                    subscribers[publisher_id].splice(index, 1);
                }
            }
        }
    };

    return that;
};
<|endoftext|>


<commit_before>// @flow

import type {OfficeHours, DirectoryItem} from './types'
import {entities} from '@frogpond/html-lib'

export const prefixTitle = (prefix: string) => {
	return prefix.endsWith(':') ? prefix.slice(0, -1) : prefix
}

export const officeHoursTitle = (officeHours: OfficeHours) => {
	let content = officeHours.content || ''
	let label = officeHours.hrefLabel || ''

	return `${content} ${label}`
}

export const descriptionText = (shortRoom: string, item: DirectoryItem) => {
	let description =
		shortRoom && item.title
			? `${shortRoom} • ${item.title}`
			: shortRoom
			? shortRoom
			: item.title

	return description && entities.decode(description)
}

export const shortRoomText = (item: DirectoryItem) => {
	return item.campusLocations
		.map(loc => `${loc.buildingabbr} ${loc.room}`.trim())
		.join(' / ')
}
<commit_msg>Nix directory helpers (moved to proxied endpoint)<commit_after><|endoftext|>


<commit_before>export default class ExecutionContext {
  constructor(executor) {
    this.executor = executor;
    this.queue = [];
    this.current = Promise.resolve();
  }

  execute(routine) {
    return new Promise((resolve, reject) => {
      this.queue.push(new Task(routine, resolve, reject));
      if (this.queue.length === 1) this.flush();
    });
  }

  flush() {
    this.current = this.current.then(() => {
      return this.executor.execute(this.queue);
    });
  }
}

class Task {
  constructor(routine, resolve, reject) {
    this.routine = routine;
    this.resolve = resolve;
    this.reject = reject;
  }

  run() {
    try {
      this.resolve(this.routine());
    } catch (error) {
      this.reject(error);
    }
  }
}
<commit_msg>don't run waste<commit_after>export default class ExecutionContext {
  constructor(executor) {
    this.executor = executor;
    this.queue = [];
    this.current = Promise.resolve();
  }

  execute(routine) {
    return new Promise((resolve, reject) => {
      this.queue.push(new Task(routine, resolve, reject));
      if (this.queue.length === 1) this.flush();
    });
  }

  flush() {
    this.current = this.current.then(() => {
      if (this.queue.length > 0) {
        return this.executor.execute(this.queue);
      }
    });
  }
}

class Task {
  constructor(routine, resolve, reject) {
    this.routine = routine;
    this.resolve = resolve;
    this.reject = reject;
  }

  run() {
    try {
      this.resolve(this.routine());
    } catch (error) {
      this.reject(error);
    }
  }
}
<|endoftext|>


<commit_before>const webpackConfig = require('./webpack.config.js');
require('babel-polyfill');  // eslint-disable-line import/no-extraneous-dependencies

module.exports = (config) => {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],

    files: [
      'node_modules/babel-polyfill/dist/polyfill.js',
      'node_modules/react/umd/react.development.js',
      'node_modules/react-dom/umd/react-dom.development.js',
      'node_modules/pixi.js/dist/pixi.js',
      'node_modules/react-bootstrap/dist/react-bootstrap.js',
      'node_modules/bootstrap/dist/css/bootstrap.min.css',
      'build/hglib.css',
      'test/**/*.+(js|jsx)',
      // 'test/PngExportTest.js',
       // 'test/OSMTests.js',
      // 'test/TiledPixiTrackTests.js',
      // 'test/ViewManipulationTests.js',
      // 'test/ChromSizesTests.js',
      // 'test/ViewportProjectionTests.js',
      // 'test/APITests.js',
      // 'test/AddAndRemoveViewconfTests.js',
      // 'test/HiGlassComponentTest.js',
      // 'test/HiGlassComponentCreationTests.js',
    ],

    preprocessors: {
      // add webpack as preprocessor
      'app/scripts/**/*.+(js|jsx)': ['webpack', 'sourcemap'],
      'test/**/*.+(js|jsx)': ['webpack', 'sourcemap'],
    },

    webpack: webpackConfig,

    webpackServer: {
      noInfo: true, // please don't spam the console when running in karma!
    },

    plugins: [
      'karma-webpack',
      'karma-jasmine',
      'karma-sourcemap-loader',
      'karma-chrome-launcher',
      'karma-phantomjs2-launcher',
    ],

    babelPreprocessor: {
      options: {
        presets: ['airbnb'],
      },
    },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_DEBUG,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    customLaunchers: {
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox'],
      },
    },
  });

  if (process.env.TRAVIS) {
    config.browsers = ['Chrome_travis_ci'];
  }
};
<commit_msg>Fix indent<commit_after>const webpackConfig = require('./webpack.config.js');
require('babel-polyfill');  // eslint-disable-line import/no-extraneous-dependencies

module.exports = (config) => {
  config.set({
    basePath: '',
    frameworks: ['jasmine'],

    files: [
      'node_modules/babel-polyfill/dist/polyfill.js',
      'node_modules/react/umd/react.development.js',
      'node_modules/react-dom/umd/react-dom.development.js',
      'node_modules/pixi.js/dist/pixi.js',
      'node_modules/react-bootstrap/dist/react-bootstrap.js',
      'node_modules/bootstrap/dist/css/bootstrap.min.css',
      'build/hglib.css',
      'test/**/*.+(js|jsx)',
      // 'test/PngExportTest.js',
      // 'test/OSMTests.js',
      // 'test/TiledPixiTrackTests.js',
      // 'test/ViewManipulationTests.js',
      // 'test/ChromSizesTests.js',
      // 'test/ViewportProjectionTests.js',
      // 'test/APITests.js',
      // 'test/AddAndRemoveViewconfTests.js',
      // 'test/HiGlassComponentTest.js',
      // 'test/HiGlassComponentCreationTests.js',
    ],

    preprocessors: {
      // add webpack as preprocessor
      'app/scripts/**/*.+(js|jsx)': ['webpack', 'sourcemap'],
      'test/**/*.+(js|jsx)': ['webpack', 'sourcemap'],
    },

    webpack: webpackConfig,

    webpackServer: {
      noInfo: true, // please don't spam the console when running in karma!
    },

    plugins: [
      'karma-webpack',
      'karma-jasmine',
      'karma-sourcemap-loader',
      'karma-chrome-launcher',
      'karma-phantomjs2-launcher',
    ],

    babelPreprocessor: {
      options: {
        presets: ['airbnb'],
      },
    },
    reporters: ['progress'],
    port: 9876,
    colors: true,
    logLevel: config.LOG_DEBUG,
    autoWatch: true,
    browsers: ['Chrome'],
    singleRun: false,
    customLaunchers: {
      Chrome_travis_ci: {
        base: 'Chrome',
        flags: ['--no-sandbox'],
      },
    },
  });

  if (process.env.TRAVIS) {
    config.browsers = ['Chrome_travis_ci'];
  }
};
<|endoftext|>


<commit_before>Meteor.subscribe('cards');
Meteor.subscribe('lists');
Meteor.subscribe('stories');

story_id = parseInt(getUrlVars()["id"]);

function getUrlVars() {
	var vars = [], hash;
	var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	for(var i = 0; i < hashes.length; i++) {
		hash = hashes[i].split('=');
		if($.inArray(hash[0], vars)>-1) {
			vars[hash[0]]+=","+hash[1];
		}
		else {
			vars.push(hash[0]);
			vars[hash[0]] = hash[1];
		}
	}
	return vars;
}

Template.board.helpers({
	lists: Lists.find({}, {sort: {order: 1}})
});

Template.list.cards = function(status) {
	list_name = Lists.findOne({_id: status}).name;
	return Cards.find({status: list_name},
		{sort: {position: 1, task: 1}}
            );
};

Template.page_title.helpers({
	title: function () {
		if(story_id)
			return Stories.findOne({"id": story_id}).title;
		else
			return "All Tasks";
	}
});

if(story_id) {
	Meteor.call("fetchTask", "story_id", story_id, function (error, result) {
		if (error) console.log(error);
		//else alert(result);
	});
}
else {
	Meteor.call("fetchAllTasks", function (error, result) {
		if (error) console.log(error);
		//else alert(result);
	});
}
<commit_msg>title when id does not correspond to story<commit_after>Meteor.subscribe('cards');
Meteor.subscribe('lists');
Meteor.subscribe('stories');

story_id = parseInt(getUrlVars()["id"]);

function getUrlVars() {
	var vars = [], hash;
	var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
	for(var i = 0; i < hashes.length; i++) {
		hash = hashes[i].split('=');
		if($.inArray(hash[0], vars)>-1) {
			vars[hash[0]]+=","+hash[1];
		}
		else {
			vars.push(hash[0]);
			vars[hash[0]] = hash[1];
		}
	}
	return vars;
}

Template.board.helpers({
	lists: Lists.find({}, {sort: {order: 1}})
});

Template.list.cards = function(status) {
	list_name = Lists.findOne({_id: status}).name;
	return Cards.find({status: list_name},
		{sort: {position: 1, task: 1}}
            );
};

Template.page_title.helpers({
	title: function () {
		if(story_id) {
			story_doc = Stories.findOne({"id": story_id});
			if(story_doc)
				return story_doc.title;
			else
				return "Cannot Find Task";
		}
		else
			return "All Tasks";
	}
});

if(story_id) {
	Meteor.call("fetchTask", "story_id", story_id, function (error, result) {
		if (error) console.log(error);
		//else alert(result);
	});
}
else {
	Meteor.call("fetchAllTasks", function (error, result) {
		if (error) console.log(error);
		//else alert(result);
	});
}
<|endoftext|>