<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const Promise = require('promise');
const Server = require('../Server');
const bser = require('bser');
const debug = require('debug')('ReactPackager:SocketServer');
const fs = require('fs');
const net = require('net');

const MAX_IDLE_TIME = 30 * 1000;
const MAX_STARTUP_TIME = 5 * 60 * 1000;

class SocketServer {
  constructor(sockPath, options) {
    this._server = net.createServer();
    this._server.listen(sockPath);
    this._ready = new Promise((resolve, reject) => {
      this._server.on('error', (e) => reject(e));
      this._server.on('listening', () => {
        debug(
          'Process %d listening on socket path %s ' +
          'for server with options %j',
          process.pid,
          sockPath,
          options
        );
        resolve(this);
        process.on('exit', () => fs.unlinkSync(sockPath));
      });
    });

    this._numConnections = 0;
    this._server.on('connection', (sock) => this._handleConnection(sock));

    // Disable the file watcher.
    options.nonPersistent = true;
    this._packagerServer = new Server(options);
    this._jobs = 0;
    this._dieEventually(MAX_STARTUP_TIME);
  }

  onReady() {
    return this._ready;
  }

  _handleConnection(sock) {
    debug('connection to server', process.pid);
    this._numConnections++;
    sock.on('close', () => this._numConnections--);

    const bunser = new bser.BunserBuf();
    sock.on('data', (buf) => bunser.append(buf));
    bunser.on('value', (m) => this._handleMessage(sock, m));
    bunser.on('error', (e) => {
      e.message = 'Unhandled error from the bser buffer. ' +
                  'Either error on encoding or message handling: \n' +
                  e.message;
      throw e;
    });
  }

  _handleMessage(sock, m) {
    if (!m || !m.id || !m.data) {
      console.error('SocketServer recieved a malformed message: %j', m);
      return;
    }

    debug('got request', m);

    // Debounce the kill timer.
    this._dieEventually();

    const handleError = (error) => {
      debug('request error', error);
      this._jobs--;
      this._reply(sock, m.id, 'error', error.stack);

      // Fatal error from JSTransformer transform workers.
      if (error.type === 'ProcessTerminatedError') {
        setImmediate(() => process.exit(1));
      }
    };

    switch (m.type) {
      case 'getDependencies':
        this._jobs++;
        this._packagerServer.getDependencies(m.data).then(
          ({ dependencies }) => this._reply(sock, m.id, 'result', dependencies),
          handleError,
        );
        break;

      case 'buildBundle':
        this._jobs++;
        this._packagerServer.buildBundle(m.data).then(
          (result) => this._reply(sock, m.id, 'result', result),
          handleError,
        );
        break;

      default:
        this._reply(sock, m.id, 'error', 'Unknown message type: ' + m.type);
    }
  }

  _reply(sock, id, type, data) {
    debug('request finished', type);

    this._jobs--;
    data = toJSON(data);

    sock.write(bser.dumpToBuffer({
      id,
      type,
      data,
    }));
  }

  _dieEventually(delay = MAX_IDLE_TIME) {
    clearTimeout(this._deathTimer);
    this._deathTimer = setTimeout(() => {
      if (this._jobs <= 0 && this._numConnections <= 0) {
        debug('server dying', process.pid);
        process.exit();
      }
      this._dieEventually();
    }, delay);
  }

  static listenOnServerIPCMessages() {
    process.on('message', (message) => {
      if (!(message && message.type && message.type === 'createSocketServer')) {
        return;
      }

      debug('server got ipc message', message);

      const {options, sockPath} = message.data;
      // regexp doesn't naturally serialize to json.
      options.blacklistRE = new RegExp(options.blacklistRE.source);

      new SocketServer(sockPath, options).onReady().then(
        () => {
          debug('succesfully created server');
          process.send({ type: 'createdServer' });
        },
        error => {
          if (error.code === 'EADDRINUSE' || error.code === 'EEXIST') {
            // Server already listening, this may happen if multiple
            // clients where started in quick succussion (buck).
            process.send({ type: 'createdServer' });

            // Kill this server because some other server with the same
            // config and socket already started.
            debug('server already started');
            setImmediate(() => process.exit());
          } else {
            debug('error creating server', error.code);
            throw error;
          }
        }
      ).done();
    });
  }
}

// TODO move this to bser code.
function toJSON(object) {
  if (!(object && typeof object === 'object')) {
    return object;
  }

  if (object.toJSON) {
    return object.toJSON();
  }

  for (var p in object) {
    object[p] = toJSON(object[p]);
  }

  return object;
}

module.exports = SocketServer;
<commit_msg>defeat race condition when replying to client<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
'use strict';

const Promise = require('promise');
const Server = require('../Server');
const bser = require('bser');
const debug = require('debug')('ReactPackager:SocketServer');
const fs = require('fs');
const net = require('net');

const MAX_IDLE_TIME = 30 * 1000;
const MAX_STARTUP_TIME = 5 * 60 * 1000;

class SocketServer {
  constructor(sockPath, options) {
    this._server = net.createServer();
    this._server.listen(sockPath);
    this._ready = new Promise((resolve, reject) => {
      this._server.on('error', (e) => reject(e));
      this._server.on('listening', () => {
        debug(
          'Process %d listening on socket path %s ' +
          'for server with options %j',
          process.pid,
          sockPath,
          options
        );
        resolve(this);
        process.on('exit', () => fs.unlinkSync(sockPath));
      });
    });

    this._numConnections = 0;
    this._server.on('connection', (sock) => this._handleConnection(sock));

    // Disable the file watcher.
    options.nonPersistent = true;
    this._packagerServer = new Server(options);
    this._jobs = 0;
    this._dieEventually(MAX_STARTUP_TIME);
  }

  onReady() {
    return this._ready;
  }

  _handleConnection(sock) {
    debug('connection to server', process.pid);
    this._numConnections++;
    sock.on('close', () => this._numConnections--);

    const bunser = new bser.BunserBuf();
    sock.on('data', (buf) => bunser.append(buf));
    bunser.on('value', (m) => this._handleMessage(sock, m));
    bunser.on('error', (e) => {
      e.message = 'Unhandled error from the bser buffer. ' +
                  'Either error on encoding or message handling: \n' +
                  e.message;
      throw e;
    });
  }

  _handleMessage(sock, m) {
    if (!m || !m.id || !m.data) {
      console.error('SocketServer recieved a malformed message: %j', m);
      return;
    }

    debug('got request', m);

    // Debounce the kill timer.
    this._dieEventually();

    const handleError = (error) => {
      debug('request error', error);
      this._jobs--;
      this._reply(sock, m.id, 'error', error.stack);

      // Fatal error from JSTransformer transform workers.
      if (error.type === 'ProcessTerminatedError') {
        setImmediate(() => process.exit(1));
      }
    };

    switch (m.type) {
      case 'getDependencies':
        this._jobs++;
        this._packagerServer.getDependencies(m.data).then(
          ({ dependencies }) => this._reply(sock, m.id, 'result', dependencies),
          handleError,
        );
        break;

      case 'buildBundle':
        this._jobs++;
        this._packagerServer.buildBundle(m.data).then(
          (result) => this._reply(sock, m.id, 'result', result),
          handleError,
        );
        break;

      default:
        this._reply(sock, m.id, 'error', 'Unknown message type: ' + m.type);
    }
  }

  _reply(sock, id, type, data) {
    debug('request finished', type);

    data = toJSON(data);

    sock.write(bser.dumpToBuffer({
      id,
      type,
      data,
    }));

    // Debounce the kill timer to make sure all the bytes are sent through
    // the socket and the client has time to fully finish and disconnect.
    this._dieEventually();
    this._jobs--;
  }

  _dieEventually(delay = MAX_IDLE_TIME) {
    clearTimeout(this._deathTimer);
    this._deathTimer = setTimeout(() => {
      if (this._jobs <= 0 && this._numConnections <= 0) {
        debug('server dying', process.pid);
        process.exit();
      }
      this._dieEventually();
    }, delay);
  }

  static listenOnServerIPCMessages() {
    process.on('message', (message) => {
      if (!(message && message.type && message.type === 'createSocketServer')) {
        return;
      }

      debug('server got ipc message', message);

      const {options, sockPath} = message.data;
      // regexp doesn't naturally serialize to json.
      options.blacklistRE = new RegExp(options.blacklistRE.source);

      new SocketServer(sockPath, options).onReady().then(
        () => {
          debug('succesfully created server');
          process.send({ type: 'createdServer' });
        },
        error => {
          if (error.code === 'EADDRINUSE' || error.code === 'EEXIST') {
            // Server already listening, this may happen if multiple
            // clients where started in quick succussion (buck).
            process.send({ type: 'createdServer' });

            // Kill this server because some other server with the same
            // config and socket already started.
            debug('server already started');
            setImmediate(() => process.exit());
          } else {
            debug('error creating server', error.code);
            throw error;
          }
        }
      ).done();
    });
  }
}

// TODO move this to bser code.
function toJSON(object) {
  if (!(object && typeof object === 'object')) {
    return object;
  }

  if (object.toJSON) {
    return object.toJSON();
  }

  for (var p in object) {
    object[p] = toJSON(object[p]);
  }

  return object;
}

module.exports = SocketServer;
<|endoftext|>


<commit_before>/* @flow */

import type { NodePath } from "babel-traverse";
import nameFunction from "babel-helper-function-name";
import template from "babel-template";
import * as t from "babel-types";

let buildWrapper = template(`
  (function () {
    var ref = FUNCTION;
    return function (PARAMS) {
      return ref.apply(this, arguments);
    };
  })
`);

let awaitVisitor = {
  Function(path) {
    path.skip();
  },

  AwaitExpression({ node }) {
    node.type = "YieldExpression";
  }
};

function classOrObjectMethod(path: NodePath, callId: Object) {
  let node = path.node;
  let body = node.body;

  node.async = false;

  let container = t.functionExpression(null, [], t.blockStatement(body.body), true);
  container.shadow = true;
  body.body = [
    t.returnStatement(t.callExpression(
      t.callExpression(callId, [container]),
      []
    ))
  ];
}

function plainFunction(path: NodePath, callId: Object) {
  let node = path.node;

  if (path.isArrowFunctionExpression()) {
    path.arrowFunctionToShadowed();
  }

  node.async = false;
  node.generator = true;

  let asyncFnId = node.id;
  node.id = null;

  let built = t.callExpression(callId, [node]);
  let container = buildWrapper({
    FUNCTION: built,
    PARAMS: node.params.map(() => path.scope.generateUidIdentifier("x"))
  }).expression;

  let retFunction = container.body.body[1].argument;

  if (path.isFunctionDeclaration()) {
    node.type = "FunctionExpression";

    let declar = t.variableDeclaration("let", [
      t.variableDeclarator(
        t.identifier(asyncFnId.name),
        t.callExpression(container, [])
      )
    ]);
    declar._blockHoist = true;

    retFunction.id = asyncFnId;
    path.replaceWith(declar);
  } else {
    if (asyncFnId && asyncFnId.name) {
      retFunction.id = asyncFnId;
    } else {
      nameFunction({
        node: retFunction,
        parent: path.parent,
        scope: path.scope
      });
    }

    if (retFunction.id || node.params.length) {
      // we have an inferred function id or params so we need this wrapper
      path.replaceWith(t.callExpression(container, []));
    } else {
      // we can omit this wrapper as the conditions it protects for do not apply
      path.replaceWith(built);
    }
  }
}

export default function (path: NodePath, callId: Object) {
  let node = path.node;
  if (node.generator) return;

  path.traverse(awaitVisitor);

  if (path.isClassMethod() || path.isObjectMethod()) {
    return classOrObjectMethod(path, callId);
  } else {
    return plainFunction(path, callId);
  }
}
<commit_msg>Fix babel-helper-remap-async-to-generator to not fail with the new validation rules<commit_after>/* @flow */

import type { NodePath } from "babel-traverse";
import nameFunction from "babel-helper-function-name";
import template from "babel-template";
import * as t from "babel-types";

let buildWrapper = template(`
  (function () {
    var ref = FUNCTION;
    return function (PARAMS) {
      return ref.apply(this, arguments);
    };
  })
`);

let awaitVisitor = {
  Function(path) {
    path.skip();
  },

  AwaitExpression({ node }) {
    node.type = "YieldExpression";
  }
};

function classOrObjectMethod(path: NodePath, callId: Object) {
  let node = path.node;
  let body = node.body;

  node.async = false;

  let container = t.functionExpression(null, [], t.blockStatement(body.body), true);
  container.shadow = true;
  body.body = [
    t.returnStatement(t.callExpression(
      t.callExpression(callId, [container]),
      []
    ))
  ];
}

function plainFunction(path: NodePath, callId: Object) {
  let node = path.node;

  if (path.isArrowFunctionExpression()) {
    path.arrowFunctionToShadowed();
  }

  node.async = false;
  node.generator = true;

  let asyncFnId = node.id;
  node.id = null;

  let isDeclaration = path.isFunctionDeclaration();

  if (isDeclaration) {
    node.type = "FunctionExpression";
  }

  let built = t.callExpression(callId, [node]);
  let container = buildWrapper({
    FUNCTION: built,
    PARAMS: node.params.map(() => path.scope.generateUidIdentifier("x"))
  }).expression;

  let retFunction = container.body.body[1].argument;

  if (isDeclaration) {
    let declar = t.variableDeclaration("let", [
      t.variableDeclarator(
        t.identifier(asyncFnId.name),
        t.callExpression(container, [])
      )
    ]);
    declar._blockHoist = true;

    retFunction.id = asyncFnId;
    path.replaceWith(declar);
  } else {
    if (asyncFnId && asyncFnId.name) {
      retFunction.id = asyncFnId;
    } else {
      nameFunction({
        node: retFunction,
        parent: path.parent,
        scope: path.scope
      });
    }

    if (retFunction.id || node.params.length) {
      // we have an inferred function id or params so we need this wrapper
      path.replaceWith(t.callExpression(container, []));
    } else {
      // we can omit this wrapper as the conditions it protects for do not apply
      path.replaceWith(built);
    }
  }
}

export default function (path: NodePath, callId: Object) {
  let node = path.node;
  if (node.generator) return;

  path.traverse(awaitVisitor);

  if (path.isClassMethod() || path.isObjectMethod()) {
    return classOrObjectMethod(path, callId);
  } else {
    return plainFunction(path, callId);
  }
}
<|endoftext|>


<commit_before>/* @flow */

import * as t from 'babel-types';
import Entity from './Entity';
import type {EntityType} from './Entity';
import type {Node, NodePath} from 'babel-traverse';

const boxedIdentifiers: WeakSet<Node> = new WeakSet();

export default class ConversionContext {

  libraryName: string = 'flow-runtime';
  libraryId: string = 't';
  shouldImport: boolean = true;
  shouldAssert: boolean = true;
  shouldWarn: boolean = false;
  shouldDecorate: boolean = true;
  suppressCommentPatterns: RegExp[] = [/\$FlowFixMe/];
  suppressTypeNames: string[] = ['$FlowFixMe'];

  /**
   * A map of global entity definitions.
   * This is used to represent references to known global identifiers
   * such as `Array`, `RegExp` etc.
   */
  globalEntities: Map<string, Entity> = new Map();

  /**
   * A set of nodes that have already been visited.
   */
  visited: WeakSet<Node> = new WeakSet();

  /**
   * Mark a particular node (an Identifier) as boxed.
   * Only applies to identifiers.
   * Boxed identifiers are wrapped in `t.box()` to avoid
   * Temporal Dead Zone issues.
   */
  markBoxed (node: Node) {
    boxedIdentifiers.add(node);
  }

  /**
   * Determine whether the given node should be boxed.
   */
  isBoxed (node: Node): boolean {
    return boxedIdentifiers.has(node);
  }

  /**
   * Define a type alias with the given name and path.
   */
  defineTypeAlias (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'TypeAlias', path);
  }

  /**
   * Define a type alias with the given name and path.
   */
  defineImportedType (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'ImportedType', path);
  }

  /**
   * Define a type parameter with the given name and path.
   */
  defineTypeParameter (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'TypeParameter', path);
  }

  /**
   * Define a class type parameter with the given name and path.
   */
  defineClassTypeParameter (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'ClassTypeParameter', path);
  }

  /**
   * Define a value with the given name and path.
   */
  defineValue (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'Value', path);
  }

  /**
   * Determines whether the given node path should be ignored
   * based on its comments.
   */
  shouldSuppressPath (path: NodePath) {
    const comments = getPathComments(path);
    for (const pattern of this.suppressCommentPatterns) {
      for (const comment of comments) {
        if (pattern.test(comment)) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Determine whether we should suppress types with the given name.
   */
  shouldSuppressTypeName (name: string): boolean {
    return this.suppressTypeNames.indexOf(name) !== -1;
  }

  /**
   * Determine whether the given identifier has TDZ issues.
   * e.g. referencing a `TypeAlias` before it has been defined.
   */
  hasTDZIssue (name: string, path: NodePath): boolean {
    const existingEntity = this.getEntity(name, path);
    if (existingEntity) {
      // We have an entity but we don't know whether it clashes
      // with another entity in this scope that hasn't been defined yet.
      const existingFunctionParent = existingEntity.path && existingEntity.path.getFunctionParent();
      const functionParent = path.getFunctionParent();
      if (existingEntity.scope === path.scope) {
        // if the scopes are identical this cannot clash.
        return false;
      }
      else if (existingFunctionParent && functionParent && existingFunctionParent.node === functionParent.node) {
        // flow doesn't allow block scoped type aliases
        // so if the scopes are in the same function this must be
        // an identical reference
        return false;
      }
      else {
        // We need to see if any of the block statements
        // between this node and the existing entity have
        // unvisited type aliases that override the entity we're looking at.
        return existingEntity.isGlobal
             ? this.hasForwardTypeDeclaration(name, path)
             : this.hasForwardTypeDeclaration(name, path, existingEntity.path.findParent(filterBlockParent))
             ;
      }
    }
    else {
      // There's no entity defined with that name yet
      return this.hasForwardTypeDeclaration(name, path);
    }
  }

  /**
   * Find a named type declaration which occurs "after" the `startPath`.
   */
  hasForwardTypeDeclaration (name: string, startPath: NodePath, endBlockPath?: NodePath): boolean {
    let subject = startPath.getStatementParent();
    let block = subject.parentPath;
    let body;
    while (block !== endBlockPath) {
      while (block && (!block.isBlockStatement() && !block.isProgram())) {
        subject = block;
        block = subject.parentPath;
      }
      if (!block || block === endBlockPath) {
        return false;
      }
      body = block.get('body');
      for (let i = subject.key + 1; i < body.length; i++) {
        const path = body[i];
        if (path.isTypeAlias() || path.isInterfaceDeclaration()) {
          if (path.node.id.name === name) {
            return true;
          }
        }
      }
      if (block.isProgram()) {
        // nothing left to do
        return false;
      }
      subject = block.getStatementParent();
      block = subject.parentPath;
    }
    return false;
  }

  /**
   * Define an entity with the given name, type and path.
   */
  defineEntity (name: string, type: EntityType, path: NodePath): Entity {
    const entity = new Entity();
    entity.name = name;
    entity.path = path;
    entity.type = type;
    path.scope.setData(`Entity:${name}`, entity);
    return entity;
  }

  /**
   * Get an entity with the given name in the given path.
   */
  getEntity (name: string, path: NodePath): ? Entity {
    let entity = path.scope.getData(`Entity:${name}`);
    if (entity) {
      return entity;
    }
    entity = this.globalEntities.get(name);
    if (entity) {
      return entity;
    }
    if (global[name]) {
      entity = new Entity();
      entity.name = name;
      entity.type = 'Value';
      this.globalEntities.set(name, entity);
      return entity;
    }
    else {
      return null;
    }
  }

  /**
   * Get a named symbol from the library.
   */
  symbol (name: string): Node {
    return t.memberExpression(
      t.identifier(this.libraryId),
      t.identifier(`${name}Symbol`)
    );
  }

  /**
   * Returns a `CallExpression` node invoking the given named method
   * on the runtime library, passing in the given arguments.
   */
  call (name: string, ...args: Node[]): Node {
    return t.callExpression(
      t.memberExpression(
        t.identifier(this.libraryId),
        t.identifier(name)
      ),
      args
    );
  }

  /**
   * Call `type.assert(...args)` on the given node, or `t.warn(type, ...args)`
   * if `shouldWarn` is true.
   */
  assert (subject: Node, ...args: Node[]): Node {
    if (this.shouldWarn) {
      return this.call('warn', subject, ...args);
    }
    else {
      return t.callExpression(
        t.memberExpression(
          subject,
          t.identifier('assert')
        ),
        args
      );
    }
  }

  /**
   * Replace the given path with a node,
   * and ensure the node won't be visited again.
   */
  replacePath (path: NodePath, replacement: Node) {
    this.visited.add(replacement);
    path.replaceWith(replacement);
  }
}

function filterBlockParent (item: NodePath): NodePath {
  return item.isBlockStatement() || item.isProgram();
}

function getPathComments (path: NodePath): string[] {
  //"leadingComments", "trailingComments", "innerComments"
  const comments = [];
  if (path.node.comments) {
    for (const comment of path.node.comments) {
      comments.push(comment.value || '');
    }
  }
  if (path.node.leadingComments) {
    for (const comment of path.node.leadingComments) {
      comments.push(comment.value || '');
    }
  }
  if (path.node.innerComments) {
    for (const comment of path.node.innerComments) {
      comments.push(comment.value || '');
    }
  }
  return comments;
}<commit_msg>add getClassData and setClassData for tracking metadata for particular classes<commit_after>/* @flow */

import * as t from 'babel-types';
import Entity from './Entity';
import type {EntityType} from './Entity';
import type {Node, NodePath} from 'babel-traverse';

const boxedIdentifiers: WeakSet<Node> = new WeakSet();

export default class ConversionContext {

  libraryName: string = 'flow-runtime';
  libraryId: string = 't';
  shouldImport: boolean = true;
  shouldAssert: boolean = true;
  shouldWarn: boolean = false;
  shouldDecorate: boolean = true;
  suppressCommentPatterns: RegExp[] = [/\$FlowFixMe/];
  suppressTypeNames: string[] = ['$FlowFixMe'];

  /**
   * A map of global entity definitions.
   * This is used to represent references to known global identifiers
   * such as `Array`, `RegExp` etc.
   */
  globalEntities: Map<string, Entity> = new Map();

  /**
   * A set of nodes that have already been visited.
   */
  visited: WeakSet<Node> = new WeakSet();

  /**
   * Mark a particular node (an Identifier) as boxed.
   * Only applies to identifiers.
   * Boxed identifiers are wrapped in `t.box()` to avoid
   * Temporal Dead Zone issues.
   */
  markBoxed (node: Node) {
    boxedIdentifiers.add(node);
  }

  /**
   * Determine whether the given node should be boxed.
   */
  isBoxed (node: Node): boolean {
    return boxedIdentifiers.has(node);
  }

  /**
   * Define a type alias with the given name and path.
   */
  defineTypeAlias (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'TypeAlias', path);
  }

  /**
   * Define a type alias with the given name and path.
   */
  defineImportedType (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'ImportedType', path);
  }

  /**
   * Define a type parameter with the given name and path.
   */
  defineTypeParameter (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'TypeParameter', path);
  }

  /**
   * Define a class type parameter with the given name and path.
   */
  defineClassTypeParameter (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'ClassTypeParameter', path);
  }

  /**
   * Define a value with the given name and path.
   */
  defineValue (name: string, path: NodePath): Entity {
    return this.defineEntity(name, 'Value', path);
  }

  /**
   * Determines whether the given node path should be ignored
   * based on its comments.
   */
  shouldSuppressPath (path: NodePath) {
    const comments = getPathComments(path);
    for (const pattern of this.suppressCommentPatterns) {
      for (const comment of comments) {
        if (pattern.test(comment)) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * Determine whether we should suppress types with the given name.
   */
  shouldSuppressTypeName (name: string): boolean {
    return this.suppressTypeNames.indexOf(name) !== -1;
  }

  /**
   * Determine whether the given identifier has TDZ issues.
   * e.g. referencing a `TypeAlias` before it has been defined.
   */
  hasTDZIssue (name: string, path: NodePath): boolean {
    const existingEntity = this.getEntity(name, path);
    if (existingEntity) {
      // We have an entity but we don't know whether it clashes
      // with another entity in this scope that hasn't been defined yet.
      const existingFunctionParent = existingEntity.path && existingEntity.path.getFunctionParent();
      const functionParent = path.getFunctionParent();
      if (existingEntity.scope === path.scope) {
        // if the scopes are identical this cannot clash.
        return false;
      }
      else if (existingFunctionParent && functionParent && existingFunctionParent.node === functionParent.node) {
        // flow doesn't allow block scoped type aliases
        // so if the scopes are in the same function this must be
        // an identical reference
        return false;
      }
      else {
        // We need to see if any of the block statements
        // between this node and the existing entity have
        // unvisited type aliases that override the entity we're looking at.
        return existingEntity.isGlobal
             ? this.hasForwardTypeDeclaration(name, path)
             : this.hasForwardTypeDeclaration(name, path, existingEntity.path.findParent(filterBlockParent))
             ;
      }
    }
    else {
      // There's no entity defined with that name yet
      return this.hasForwardTypeDeclaration(name, path);
    }
  }

  /**
   * Find a named type declaration which occurs "after" the `startPath`.
   */
  hasForwardTypeDeclaration (name: string, startPath: NodePath, endBlockPath?: NodePath): boolean {
    let subject = startPath.getStatementParent();
    let block = subject.parentPath;
    let body;
    while (block !== endBlockPath) {
      while (block && (!block.isBlockStatement() && !block.isProgram())) {
        subject = block;
        block = subject.parentPath;
      }
      if (!block || block === endBlockPath) {
        return false;
      }
      body = block.get('body');
      for (let i = subject.key + 1; i < body.length; i++) {
        const path = body[i];
        if (path.isTypeAlias() || path.isInterfaceDeclaration()) {
          if (path.node.id.name === name) {
            return true;
          }
        }
      }
      if (block.isProgram()) {
        // nothing left to do
        return false;
      }
      subject = block.getStatementParent();
      block = subject.parentPath;
    }
    return false;
  }

  /**
   * Define an entity with the given name, type and path.
   */
  defineEntity (name: string, type: EntityType, path: NodePath): Entity {
    const entity = new Entity();
    entity.name = name;
    entity.path = path;
    entity.type = type;
    path.scope.setData(`Entity:${name}`, entity);
    return entity;
  }

  /**
   * Get an entity with the given name in the given path.
   */
  getEntity (name: string, path: NodePath): ? Entity {
    let entity = path.scope.getData(`Entity:${name}`);
    if (entity) {
      return entity;
    }
    entity = this.globalEntities.get(name);
    if (entity) {
      return entity;
    }
    if (global[name]) {
      entity = new Entity();
      entity.name = name;
      entity.type = 'Value';
      this.globalEntities.set(name, entity);
      return entity;
    }
    else {
      return null;
    }
  }

  /**
   * Get a named symbol from the library.
   */
  symbol (name: string): Node {
    return t.memberExpression(
      t.identifier(this.libraryId),
      t.identifier(`${name}Symbol`)
    );
  }

  /**
   * Returns a `CallExpression` node invoking the given named method
   * on the runtime library, passing in the given arguments.
   */
  call (name: string, ...args: Node[]): Node {
    return t.callExpression(
      t.memberExpression(
        t.identifier(this.libraryId),
        t.identifier(name)
      ),
      args
    );
  }

  /**
   * Call `type.assert(...args)` on the given node, or `t.warn(type, ...args)`
   * if `shouldWarn` is true.
   */
  assert (subject: Node, ...args: Node[]): Node {
    if (this.shouldWarn) {
      return this.call('warn', subject, ...args);
    }
    else {
      return t.callExpression(
        t.memberExpression(
          subject,
          t.identifier('assert')
        ),
        args
      );
    }
  }

  /**
   * Replace the given path with a node,
   * and ensure the node won't be visited again.
   */
  replacePath (path: NodePath, replacement: Node) {
    this.visited.add(replacement);
    path.replaceWith(replacement);
  }

  getClassData (path: NodePath, key: string): any {
    const candidates = path.scope.getData(`classData:${key}`);
    if (candidates instanceof Map) {
      const declaration = path.isClass()
                        ? path
                        : path.findParent(item => item.isClass())
                        ;

      if (declaration) {
        return candidates.get(declaration.node);
      }
      else {
        console.warn('Could not find class declaration to get data from:', key);
      }
    }
  }

  setClassData (path: NodePath, key: string, value: any) {
    const {scope} = path;
    const qualifiedKey = `classData:${key}`;
    const declaration = path.isClass()
                      ? path
                      : path.findParent(item => item.isClass())
                      ;
    if (!declaration) {
      console.warn('Could not find class declaration to set data on:', key);
      return;
    }

    let map = scope.data[qualifiedKey];
    if (!(map instanceof Map)) {
      map = new Map();
      scope.data[qualifiedKey] = map;
    }

    map.set(declaration.node, value);
  }
}

function filterBlockParent (item: NodePath): NodePath {
  return item.isBlockStatement() || item.isProgram();
}

function getPathComments (path: NodePath): string[] {
  //"leadingComments", "trailingComments", "innerComments"
  const comments = [];
  if (path.node.comments) {
    for (const comment of path.node.comments) {
      comments.push(comment.value || '');
    }
  }
  if (path.node.leadingComments) {
    for (const comment of path.node.leadingComments) {
      comments.push(comment.value || '');
    }
  }
  if (path.node.innerComments) {
    for (const comment of path.node.innerComments) {
      comments.push(comment.value || '');
    }
  }
  return comments;
}<|endoftext|>


<commit_before>import React, {Component, PropTypes} from 'react';

/**
 * A basic HTML input control for entering text, numbers, or passwords.
 *
 * Note that checkbox and radio types are supported through
 * the Checklist and RadioItems component. Dates, times, and file uploads
 * are also supported through separate components.
 */
export default class Input extends Component {
    constructor(props) {
        super(props);
        this.state = {value: props.value};
    }

    componentWillReceiveProps(nextProps) {
        this.setState({value: nextProps.value});
    }

    render() {
        const {
            className,
            id,
            fireEvent,
            placeholder,
            style,
            type,
            setProps
        } = this.props;
        const {value} = this.state;

        return (
            <input
                className={className}
                id={id}
                type={type}
                value={value}
                placeholder={placeholder}
                style={style}
                onChange={e => {
                    this.setState({value: e.target.value});
                    if (setProps) setProps({value: e.target.value});
                    if (fireEvent) fireEvent({event: 'change'});
                }}
                onBlur={() => {
                    if (fireEvent) fireEvent({event: 'blur'});
                }}
            />
        );
    }
}

Input.propTypes = {
    /**
     * The value of the input
     */
    'id': PropTypes.string,

    /**
     * A hint to the user of what can be entered in the control.
     * Note: Do not use the placeholder attribute instead of a Label element,
     * their purposes are different.
     * The Label attribute describes the role of the form element
     * (i.e. it indicates what kind of information is expected),
     * and the placeholder attribute is a hint about the format
     * that the value should take.
     * There are cases in which the placeholder attribute is
     * never displayed to the user, so the form must be understandable
     * without it.
     */
    placeholder: PropTypes.string,
    'value': PropTypes.string,

    /**
     * The input's inline styles
     */
    'style': PropTypes.object,

    /**
     * The class of the input element
     */
    'className': PropTypes.string,

    /**
     * The type of control to render.
     */
    type: PropTypes.oneOf([
        'text', 'number', 'password'
    ]),

    /**
     * If disabled, then the input can not be edited
     */
    disabled: PropTypes.bool,

    /**
     * Dash-assigned callback that gets fired when the input changes.
     */
    fireEvent: PropTypes.func,

    /**
     * Dash-assigned callback that gets fired when the value changes.
     */
    setProps: PropTypes.func,

    dashEvents: PropTypes.oneOf(['blur', 'change'])
};
<commit_msg>add a more lengthy description of `id`<commit_after>import React, {Component, PropTypes} from 'react';

/**
 * A basic HTML input control for entering text, numbers, or passwords.
 *
 * Note that checkbox and radio types are supported through
 * the Checklist and RadioItems component. Dates, times, and file uploads
 * are also supported through separate components.
 */
export default class Input extends Component {
    constructor(props) {
        super(props);
        this.state = {value: props.value};
    }

    componentWillReceiveProps(nextProps) {
        this.setState({value: nextProps.value});
    }

    render() {
        const {
            className,
            id,
            fireEvent,
            placeholder,
            style,
            type,
            setProps
        } = this.props;
        const {value} = this.state;

        return (
            <input
                className={className}
                id={id}
                type={type}
                value={value}
                placeholder={placeholder}
                style={style}
                onChange={e => {
                    this.setState({value: e.target.value});
                    if (setProps) setProps({value: e.target.value});
                    if (fireEvent) fireEvent({event: 'change'});
                }}
                onBlur={() => {
                    if (fireEvent) fireEvent({event: 'blur'});
                }}
            />
        );
    }
}

Input.propTypes = {
    /**
     * The ID of this component, used to identify dash components
     * in callbacks. The ID needs to be unique across all of the
     * components in an app.
     */
    'id': PropTypes.string,

    /**
     * A hint to the user of what can be entered in the control.
     * Note: Do not use the placeholder attribute instead of a Label element,
     * their purposes are different.
     * The Label attribute describes the role of the form element
     * (i.e. it indicates what kind of information is expected),
     * and the placeholder attribute is a hint about the format
     * that the value should take.
     * There are cases in which the placeholder attribute is
     * never displayed to the user, so the form must be understandable
     * without it.
     */
    placeholder: PropTypes.string,
    'value': PropTypes.string,

    /**
     * The input's inline styles
     */
    'style': PropTypes.object,

    /**
     * The class of the input element
     */
    'className': PropTypes.string,

    /**
     * The type of control to render.
     */
    type: PropTypes.oneOf([
        'text', 'number', 'password'
    ]),

    /**
     * If disabled, then the input can not be edited
     */
    disabled: PropTypes.bool,

    /**
     * Dash-assigned callback that gets fired when the input changes.
     */
    fireEvent: PropTypes.func,

    /**
     * Dash-assigned callback that gets fired when the value changes.
     */
    setProps: PropTypes.func,

    dashEvents: PropTypes.oneOf(['blur', 'change'])
};
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { defineMessages } from 'react-intl';
import { Card, CardActions } from 'material-ui/Card';
import styled from 'styled-components';
import TimelineHeader from './TimelineHeader';
import AddAnnotation from './AddAnnotation';
import MediaAnnotation from './MediaAnnotation';
import Can from '../Can';
import { units, black16, white } from '../../styles/js/variables';

const messages = defineMessages({
  timelineTitle: {
    id: 'mediaComponent.verificationTimeline',
    defaultMessage: 'Verification Timeline',
  },
  bridge_timelineTitle: {
    id: 'bridge.mediaComponent.verificationTimeline',
    defaultMessage: 'Translation Timeline',
  },
});

const StyledCard = styled(Card)`
  display: flex;
  flex-direction: column;
`;

const StyledCardActions = styled(CardActions)`
  margin-top: auto;
  background-color: ${white};
  border-top: 1px solid ${black16};
`;

class Annotations extends Component {
  annotationComponent(node, annotated, annotatedType) {
    return (
      <MediaAnnotation
        annotation={node}
        annotated={annotated}
        annotatedType={annotatedType}
      />
    );
  }

  render() {
    const props = this.props;
    const annotations = props.annotations;

    return (

      </StyledCard>
    );
  }
}

export default Annotations;
<commit_msg>#6168 Improve padding on annotations list<commit_after>import React, { Component } from 'react';
import { defineMessages } from 'react-intl';
import { Card, CardActions } from 'material-ui/Card';
import styled from 'styled-components';
import TimelineHeader from './TimelineHeader';
import AddAnnotation from './AddAnnotation';
import MediaAnnotation from './MediaAnnotation';
import Can from '../Can';
import { units, black16, white } from '../../styles/js/variables';

const messages = defineMessages({
  timelineTitle: {
    id: 'mediaComponent.verificationTimeline',
    defaultMessage: 'Verification Timeline',
  },
  bridge_timelineTitle: {
    id: 'bridge.mediaComponent.verificationTimeline',
    defaultMessage: 'Translation Timeline',
  },
});

const StyledCard = styled(Card)`
  display: flex;
  flex-direction: column;
`;

const StyledCardActions = styled(CardActions)`
  margin-top: auto;
  background-color: ${white};
  border-top: 1px solid ${black16};
`;

class Annotations extends Component {
  annotationComponent(node, annotated, annotatedType) {
    return (
      <MediaAnnotation
        annotation={node}
        annotated={annotated}
        annotatedType={annotatedType}
      />
    );
  }

  render() {
    const props = this.props;
    const annotations = props.annotations;

    return (

      </StyledCard>
    );
  }
}

export default Annotations;
<|endoftext|>


<commit_before>define( [ "ember" ], function( Ember ) {

	var	FS		= require( "fs" ),
		isWin	= /^win/.test( process.platform ),
		PATH	= process.env.PATH || process.env.Path || process.env.path || ".",
		PATHS	= PATH.split( isWin ? ";" : ":" ),
		EXTS	= [ ".exe" ]; // isWin ? process.env.PATHEXT.split( ";" ) : null;

	/**
	 * Check if the path for livestreamer is valid
	 * TODO: maybe also check if the file really is livestreamer? `livestreamer --version`
	 * @param {string} path A user defined path
	 * @param {string} exec The default command
	 * @returns {boolean|string}
	 */
	function checkLivestreamer( path, exec ) {
		// use the default command if the user did not define one
		path = path ? String( path ) : exec;

		// check for invalid values first
		return	path.indexOf( exec ) !== -1
		// then check for the executable
			&&	which( path );
	}

	/**
	 * Locate a command
	 * @param {string} file
	 * @returns {boolean|string}
	 */
	function which( file ) {
		// absolute or relative
		if ( file.indexOf( isWin ? "\\" : "/" ) !== -1 ) {
			return checkFile( file ) && file;

		// search in every PATH
		} else {
			var check, j, i = 0, l = PATHS.length, m = EXTS.length;
			if ( isWin ) {
				for ( ; i < l; i++ ) {
					for ( j = 0; j < m; j++ ) {
						check = PATHS[ i ] + "\\" + file + EXTS[ j ];
						if ( checkFile( check ) ) {
							return check;
						}
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					check = PATHS[ i ] + "/" + file;
					if ( checkFile( check ) ) {
						return check;
					}
				}
			}

			return false;
		}
	}

	/**
	 * Does the file exist and is it executable?
	 * @param {string} file
	 * @returns {boolean}
	 */
	function checkFile( file ) {
		if ( !FS.existsSync( file ) ) { return false; }
		var stat = FS.statSync( file );
		return	stat.isFile()
			&&	!isWin
				// check for executable flag on non-windows
				? stat.mode & 0111
				// ?
				: true;
	}

	return Ember.ObjectController.extend({
		needs: [ "application", "modal" ],

		model: function() {
			return this.get( "controllers.application.model" );
		}.property( "controllers.application.model" ),

		parameters: [
			{
				arg		: "--player",
				params	: [ "player" ],
				cond	: [ "player" ]
			},
			{
				arg		: "--player-args",
				params	: [ "player_params" ],
				cond	: [ "player", "player_params" ]
			},
			{
				arg		: "--player-continuous-http",
				params	: [],
				cond	: [ "player_reconnect" ]
			},
			{
				arg		: "--player-no-close",
				params	: [],
				cond	: [ "player_no_close" ]
			}
		],

		actions: {
			start: function( settings, stream ) {
				var	livestreamer,
					command,

					modal = this.get( "controllers.modal" ),
					exec = this.get( "model.package.config.livestreamer-exec" ),
					path = settings.get( "livestreamer" ),

					qualities = settings.get( "qualities" ),
					quality = settings.get( "quality" ),
					args = [];

				// Prepare parameters
				this.parameters.forEach(function( elem ) {
					if ( elem.cond.every(function( cond ) {
						return !!settings.get( cond );
					}) ) {
						[].push.apply( args, [ elem.arg ].concat(
							elem.params.map(function( param ) {
								return settings.get( param );
							}) )
						);
					}
				});

				args = args.concat([
					stream.channel.url,
					qualities.hasOwnProperty( quality )
						? qualities[ quality ].quality
						: qualities[ 0 ].quality
				]);

				function kill() {
					livestreamer && livestreamer.kill( "SIGTERM" );
				}

				// Dialog
				this.send( "openModal",
					"Preparing",
					"Please wait...",
					[ new modal.Button( "Close", "btn-danger", "fa-times", kill ) ]
				);

				// prepare the command and validate
				command = checkLivestreamer( path, exec );
				if ( !command ) {
					this.send( "updateModal",
						"Error: Livestreamer was not found",
						"Please check settings and/or (re)install Livestreamer."
					);

				} else {
					this.send( "updateModal",
						"Watching now: " + stream.channel.name,
						stream.channel.status
					);

					// start the child process
					livestreamer = require( "child_process" ).spawn( command, args );

					livestreamer && livestreamer.on( "exit", function () {
						this.send( "closeModal" );
					}.bind( this ) );
				}
			}
		}
	});

});
<commit_msg>Fixed LivestreamerController reading computed properties<commit_after>define( [ "ember" ], function( Ember ) {

	var	FS		= require( "fs" ),
		isWin	= /^win/.test( process.platform ),
		PATH	= process.env.PATH || process.env.Path || process.env.path || ".",
		PATHS	= PATH.split( isWin ? ";" : ":" ),
		EXTS	= [ ".exe" ]; // isWin ? process.env.PATHEXT.split( ";" ) : null;

	/**
	 * Check if the path for livestreamer is valid
	 * TODO: maybe also check if the file really is livestreamer? `livestreamer --version`
	 * @param {string} path A user defined path
	 * @param {string} exec The default command
	 * @returns {boolean|string}
	 */
	function checkLivestreamer( path, exec ) {
		// use the default command if the user did not define one
		path = path ? String( path ) : exec;

		// check for invalid values first
		return	path.indexOf( exec ) !== -1
		// then check for the executable
			&&	which( path );
	}

	/**
	 * Locate a command
	 * @param {string} file
	 * @returns {boolean|string}
	 */
	function which( file ) {
		// absolute or relative
		if ( file.indexOf( isWin ? "\\" : "/" ) !== -1 ) {
			return checkFile( file ) && file;

		// search in every PATH
		} else {
			var check, j, i = 0, l = PATHS.length, m = EXTS.length;
			if ( isWin ) {
				for ( ; i < l; i++ ) {
					for ( j = 0; j < m; j++ ) {
						check = PATHS[ i ] + "\\" + file + EXTS[ j ];
						if ( checkFile( check ) ) {
							return check;
						}
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					check = PATHS[ i ] + "/" + file;
					if ( checkFile( check ) ) {
						return check;
					}
				}
			}

			return false;
		}
	}

	/**
	 * Does the file exist and is it executable?
	 * @param {string} file
	 * @returns {boolean}
	 */
	function checkFile( file ) {
		if ( !FS.existsSync( file ) ) { return false; }
		var stat = FS.statSync( file );
		return	stat.isFile()
			&&	!isWin
				// check for executable flag on non-windows
				? stat.mode & 0111
				// ?
				: true;
	}

	return Ember.ObjectController.extend({
		needs: [ "application", "modal" ],

		model: function() {
			return this.get( "controllers.application.model" );
		}.property( "controllers.application.model" ),

		parameters: [
			{
				arg		: "--player",
				params	: [ "player" ],
				cond	: [ "player" ]
			},
			{
				arg		: "--player-args",
				params	: [ "player_params" ],
				cond	: [ "player", "player_params" ]
			},
			{
				arg		: "--player-continuous-http",
				params	: [],
				cond	: [ "player_reconnect" ]
			},
			{
				arg		: "--player-no-close",
				params	: [],
				cond	: [ "player_no_close" ]
			}
		],

		actions: {
			start: function( settings, stream ) {
				var	livestreamer,
					command,

					modal = this.get( "controllers.modal" ),
					exec = this.get( "model.package.config.livestreamer-exec" ),
					path = settings.get( "livestreamer" ),

					qualities = settings.get( "qualities" ),
					quality = settings.get( "quality" ),
					args = [];

				// Prepare parameters
				this.parameters.forEach(function( elem ) {
					if ( elem.cond.every(function( cond ) {
						return !!settings.get( cond );
					}) ) {
						[].push.apply( args, [ elem.arg ].concat(
							elem.params.map(function( param ) {
								return settings.get( param );
							}) )
						);
					}
				});

				args = args.concat([
					Ember.get( stream, "channel.url" ),
					qualities.hasOwnProperty( quality )
						? qualities[ quality ].quality
						: qualities[ 0 ].quality
				]);

				function kill() {
					livestreamer && livestreamer.kill( "SIGTERM" );
				}

				// Dialog
				this.send( "openModal",
					"Preparing",
					"Please wait...",
					[ new modal.Button( "Close", "btn-danger", "fa-times", kill ) ]
				);

				// prepare the command and validate
				command = checkLivestreamer( path, exec );
				if ( !command ) {
					this.send( "updateModal",
						"Error: Livestreamer was not found",
						"Please check settings and/or (re)install Livestreamer."
					);

				} else {
					this.send( "updateModal",
						"Watching now: " + Ember.get( stream, "channel.name" ),
						Ember.get( stream, "channel.status" )
					);

					// start the child process
					livestreamer = require( "child_process" ).spawn( command, args );

					livestreamer && livestreamer.on( "exit", function () {
						this.send( "closeModal" );
					}.bind( this ) );
				}
			}
		}
	});

});
<|endoftext|>


<commit_before>define( [ "ember" ], function( Ember ) {

	var	FS		= require( "fs" ),
		isWin	= /win/.test( process.platform ),
		PATH	= process.env.PATH || process.env.Path || process.env.path || ".",
		PATHS	= PATH.split( isWin ? ";" : ":" ),
		EXTS	= [ ".exe" ]; // isWin ? process.env.PATHEXT.split( ";" ) : null;

	/**
	 * Check if the path for livestreamer is valid
	 * TODO: maybe also check if the file really is livestreamer? `livestreamer --version`
	 * @param {string} path A user defined path
	 * @param {string} exec The default command
	 * @returns {boolean|string}
	 */
	function checkLivestreamer( path, exec ) {
		// use the default command if the user did not define one
		path = path ? String( path ) : exec;

		// check for invalid values first
		return	path.indexOf( exec ) !== -1
		// then check for the executable
			&&	which( path );
	}

	/**
	 * Locate a command
	 * @param {string} file
	 * @returns {boolean|string}
	 */
	function which( file ) {
		// absolute or relative
		if ( file.indexOf( isWin ? "\\" : "/" ) !== -1 ) {
			return checkFile( file ) && file;

		// search in every PATH
		} else {
			var check, j, i = 0, l = PATHS.length, m = EXTS.length;
			if ( isWin ) {
				for ( ; i < l; i++ ) {
					for ( j = 0; j < m; j++ ) {
						check = PATHS[ i ] + "\\" + file + EXTS[ j ];
						if ( checkFile( check ) ) {
							return check;
						}
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					check = PATHS[ i ] + "/" + file;
					if ( checkFile( check ) ) {
						return check;
					}
				}
			}

			return false;
		}
	}

	/**
	 * Does the file exist and is it executable?
	 * @param {string} file
	 * @returns {boolean}
	 */
	function checkFile( file ) {
		if ( !FS.existsSync( file ) ) { return false; }
		var stat = FS.statSync( file );
		return	stat.isFile()
			&&	!isWin
				// check for executable flag on non-windows
				? stat.mode & 0111
				// ?
				: true;
	}

	return Ember.ObjectController.extend({
		needs: [ "application", "modal" ],

		model: function() {
			return this.get( "controllers.application.model" );
		}.property( "controllers.application.model" ),

		parameters: [
			{
				arg		: "--player",
				params	: [ "player" ],
				cond	: [ "player" ]
			},
			{
				arg		: "--player-args",
				params	: [ "player_params" ],
				cond	: [ "player", "player_params" ]
			},
			{
				arg		: "--player-continuous-http",
				params	: [],
				cond	: [ "player_reconnect" ]
			},
			{
				arg		: "--player-no-close",
				params	: [],
				cond	: [ "player_no_close" ]
			}
		],

		actions: {
			start: function( settings, stream ) {
				var	livestreamer,
					command,

					modal = this.get( "controllers.modal" ),
					exec = this.get( "model.package.config.livestreamer-exec" ),
					path = settings.get( "livestreamer" ),

					qualities = settings.get( "qualities" ),
					quality = settings.get( "quality" ),
					args = [];

				// Prepare parameters
				this.parameters.forEach(function( elem ) {
					if ( elem.cond.every(function( cond ) {
						return !!settings.get( cond );
					}) ) {
						[].push.apply( args, [ elem.arg ].concat(
							elem.params.map(function( param ) {
								return settings.get( param );
							}) )
						);
					}
				});

				args = args.concat([
					stream.channel.url,
					qualities.hasOwnProperty( quality )
						? qualities[ quality ].quality
						: qualities[ 0 ].quality
				]);

				// Dialog
				this.send( "openModal",
					"Preparing",
					"Please wait...",
					[ new modal.Button( "Close", "btn-danger", "fa-times", kill ) ]
				);

				// prepare the command and validate
				command = checkLivestreamer( path, exec );
				if ( !command ) {
					this.send( "updateModal",
						"Error: Livestreamer was not found",
						"Please check settings and/or (re)install Livestreamer."
					);

				} else {
					this.send( "updateModal",
						"Watching now: " + stream.channel.name,
						stream.channel.status
					);

					// start the child process
					livestreamer = require( "child_process" ).spawn( command, args );

					livestreamer && livestreamer.on( "exit", function () {
						this.send( "closeModal" );
					}.bind( this ) );
				}

				function kill() {
					livestreamer && livestreamer.kill( "SIGTERM" );
				}
			}
		}
	});

});
<commit_msg>Fix isWin test in LivestreamerController.js<commit_after>define( [ "ember" ], function( Ember ) {

	var	FS		= require( "fs" ),
		isWin	= /^win$/.test( process.platform ),
		PATH	= process.env.PATH || process.env.Path || process.env.path || ".",
		PATHS	= PATH.split( isWin ? ";" : ":" ),
		EXTS	= [ ".exe" ]; // isWin ? process.env.PATHEXT.split( ";" ) : null;

	/**
	 * Check if the path for livestreamer is valid
	 * TODO: maybe also check if the file really is livestreamer? `livestreamer --version`
	 * @param {string} path A user defined path
	 * @param {string} exec The default command
	 * @returns {boolean|string}
	 */
	function checkLivestreamer( path, exec ) {
		// use the default command if the user did not define one
		path = path ? String( path ) : exec;

		// check for invalid values first
		return	path.indexOf( exec ) !== -1
		// then check for the executable
			&&	which( path );
	}

	/**
	 * Locate a command
	 * @param {string} file
	 * @returns {boolean|string}
	 */
	function which( file ) {
		// absolute or relative
		if ( file.indexOf( isWin ? "\\" : "/" ) !== -1 ) {
			return checkFile( file ) && file;

		// search in every PATH
		} else {
			var check, j, i = 0, l = PATHS.length, m = EXTS.length;
			if ( isWin ) {
				for ( ; i < l; i++ ) {
					for ( j = 0; j < m; j++ ) {
						check = PATHS[ i ] + "\\" + file + EXTS[ j ];
						if ( checkFile( check ) ) {
							return check;
						}
					}
				}

			} else {
				for ( ; i < l; i++ ) {
					check = PATHS[ i ] + "/" + file;
					if ( checkFile( check ) ) {
						return check;
					}
				}
			}

			return false;
		}
	}

	/**
	 * Does the file exist and is it executable?
	 * @param {string} file
	 * @returns {boolean}
	 */
	function checkFile( file ) {
		if ( !FS.existsSync( file ) ) { return false; }
		var stat = FS.statSync( file );
		return	stat.isFile()
			&&	!isWin
				// check for executable flag on non-windows
				? stat.mode & 0111
				// ?
				: true;
	}

	return Ember.ObjectController.extend({
		needs: [ "application", "modal" ],

		model: function() {
			return this.get( "controllers.application.model" );
		}.property( "controllers.application.model" ),

		parameters: [
			{
				arg		: "--player",
				params	: [ "player" ],
				cond	: [ "player" ]
			},
			{
				arg		: "--player-args",
				params	: [ "player_params" ],
				cond	: [ "player", "player_params" ]
			},
			{
				arg		: "--player-continuous-http",
				params	: [],
				cond	: [ "player_reconnect" ]
			},
			{
				arg		: "--player-no-close",
				params	: [],
				cond	: [ "player_no_close" ]
			}
		],

		actions: {
			start: function( settings, stream ) {
				var	livestreamer,
					command,

					modal = this.get( "controllers.modal" ),
					exec = this.get( "model.package.config.livestreamer-exec" ),
					path = settings.get( "livestreamer" ),

					qualities = settings.get( "qualities" ),
					quality = settings.get( "quality" ),
					args = [];

				// Prepare parameters
				this.parameters.forEach(function( elem ) {
					if ( elem.cond.every(function( cond ) {
						return !!settings.get( cond );
					}) ) {
						[].push.apply( args, [ elem.arg ].concat(
							elem.params.map(function( param ) {
								return settings.get( param );
							}) )
						);
					}
				});

				args = args.concat([
					stream.channel.url,
					qualities.hasOwnProperty( quality )
						? qualities[ quality ].quality
						: qualities[ 0 ].quality
				]);

				// Dialog
				this.send( "openModal",
					"Preparing",
					"Please wait...",
					[ new modal.Button( "Close", "btn-danger", "fa-times", kill ) ]
				);

				// prepare the command and validate
				command = checkLivestreamer( path, exec );
				if ( !command ) {
					this.send( "updateModal",
						"Error: Livestreamer was not found",
						"Please check settings and/or (re)install Livestreamer."
					);

				} else {
					this.send( "updateModal",
						"Watching now: " + stream.channel.name,
						stream.channel.status
					);

					// start the child process
					livestreamer = require( "child_process" ).spawn( command, args );

					livestreamer && livestreamer.on( "exit", function () {
						this.send( "closeModal" );
					}.bind( this ) );
				}

				function kill() {
					livestreamer && livestreamer.kill( "SIGTERM" );
				}
			}
		}
	});

});
<|endoftext|>


<commit_before>import { Utils } from 'meteor/vulcan:core';
import { convertFromRaw } from 'draft-js';
import { draftToHTML } from '../../lib/editor/utils.js';
import Revisions from '../../lib/collections/revisions/collection'
import { extractVersionsFromSemver } from '../../lib/editor/utils'
import { ensureIndex } from '../../lib/collectionUtils'
import TurndownService from 'turndown';
const turndownService = new TurndownService()
turndownService.remove('style') // Make sure we don't add the content of style tags to the markdown

import markdownIt from 'markdown-it'
import markdownItMathjax from './markdown-mathjax.js'
import markdownItContainer from 'markdown-it-container'
const mdi = markdownIt({linkify: true})
mdi.use(markdownItMathjax())
mdi.use(markdownItContainer, 'spoiler')
import { addCallback } from 'meteor/vulcan:core';
import { mjpage }  from 'mathjax-node-page'

function mjPagePromise(html, beforeSerializationCallback) {
  // Takes in HTML and replaces LaTeX with CommonHTML snippets
  // https://github.com/pkra/mathjax-node-page
  return new Promise((resolve, reject) => {
    mjpage(html, {}, {html: true, css: true}, resolve)
      .on('beforeSerialization', beforeSerializationCallback);
  })
}

export async function draftJSToHtmlWithLatex(draftJS) {
  const draftJSWithLatex = await Utils.preProcessLatex(draftJS)
  return draftToHTML(convertFromRaw(draftJSWithLatex))
}

export function htmlToMarkdown(html) {
  return turndownService.turndown(html)
}

export function markdownToHtml(markdown) {
  return mdi.render(markdown)
}

export async function markdownToHtmlWithLatex(markdown) {
  const html = markdownToHtml(markdown)
  return await mjPagePromise(html, Utils.trimEmptyLatexParagraphs)
}

async function dataToHTML(data, type, sanitize = false) {
  switch (type) {
    case "html":
      return sanitize ? Utils.sanitize(data) : data
    case "draftJS":
      return await draftJSToHtmlWithLatex(data)
    case "markdown":
      return await markdownToHtmlWithLatex(data)
  }
}

export function dataToMarkdown(data, type) {
  if (!data) return ""
  switch (type) {
    case "markdown": {
      return data
    }
    case "html": {
      return htmlToMarkdown(data)
    }
    case "draftJS": {
      try {
        const contentState = convertFromRaw(data);
        const html = draftToHTML(contentState)
        return htmlToMarkdown(html)
      } catch(e) {
        // eslint-disable-next-line no-console
        console.error(e)
      }
      return ""
    }
  }
}

export async function dataToWordCount(data, type) {
  const markdown = dataToMarkdown(data, type) || ""
  return markdown.split(" ").length
}

function getInitialVersion(document) {
  if (document.draft) {
    return '0.1.0'
  } else {
    return '1.0.0'
  }
}

async function getNextVersion(documentId, updateType = 'minor') {
  const lastRevision = await Revisions.findOne({documentId: documentId}, {sort: {editedAt: -1}}) || {}
  const { major, minor, patch } = extractVersionsFromSemver(lastRevision.version)
  switch (updateType) {
    case "patch":
      return `${major}.${minor}.${patch + 1}`
    case "minor":
      return `${major}.${minor + 1}.0`
    case "major":
      return `${major+1}.0.0`
    default:
      throw new Error("Invalid updateType, must be one of 'patch', 'minor' or 'major'")
  }
}

ensureIndex(Revisions, {documentId: 1, version: 1, fieldName: 1, editedAt: 1})

export function addEditableCallbacks({collection, options = {}}) {
  const {
    fieldName = "contents",
    // deactivateNewCallback // Because of Meteor shenannigans we don't have access to the full user object when a new user is created, and this creates
    // // bugs when we register callbacks that trigger on new user creation. So we allow the deactivation of the new callbacks.
  } = options

  const { typeName } = collection.options

  async function editorSerializationNew (doc, { currentUser }) {
    if (!currentUser) { throw Error("Can't create document without current user") }
    if (doc[fieldName] && doc[fieldName].originalContents) {
      const { data, type } = doc[fieldName].originalContents
      const html = await dataToHTML(data, type, !currentUser.isAdmin)
      const wordCount = await dataToWordCount(data, type)
      const version = getInitialVersion(doc)
      const userId = currentUser._id
      const editedAt = new Date()
      return {...doc, [fieldName]: {...doc[fieldName], html, version, userId, editedAt, wordCount}}
    }
    return doc
  }

  addCallback(`${typeName.toLowerCase()}.create.before`, editorSerializationNew);

  async function editorSerializationEdit (docData, { document, currentUser }) {
    if (!currentUser) { throw Error("Can't create document without current user") }
    if (docData[fieldName] && docData[fieldName].originalContents) {
      const { data, type } = docData[fieldName].originalContents
      const html = await dataToHTML(data, type, !currentUser.isAdmin)
      const wordCount = await dataToWordCount(data, type)
      const defaultUpdateType = (document.draft && !docData.draft) ? 'major' : 'minor'
      const version = await getNextVersion(document._id, docData[fieldName].updateType || defaultUpdateType)
      const userId = currentUser._id
      const editedAt = new Date()
      return {...docData, [fieldName]: {...docData[fieldName], html, version, userId, editedAt, wordCount}}
    }
    return docData
  }

  addCallback(`${typeName.toLowerCase()}.update.before`, editorSerializationEdit);

  async function editorSerializationCreateRevision(doc) {
    if (doc[fieldName] && doc[fieldName].originalContents) {
      Revisions.insert({
        ...doc[fieldName],
        documentId: doc._id,
        fieldName
      })
    }
    return doc
  }

  addCallback(`${typeName.toLowerCase()}.create.after`, editorSerializationCreateRevision)
  addCallback(`${typeName.toLowerCase()}.update.after`, editorSerializationCreateRevision)
}
<commit_msg>Move error handling into correct scope<commit_after>import { Utils } from 'meteor/vulcan:core';
import { convertFromRaw } from 'draft-js';
import { draftToHTML } from '../../lib/editor/utils.js';
import Revisions from '../../lib/collections/revisions/collection'
import { extractVersionsFromSemver } from '../../lib/editor/utils'
import { ensureIndex } from '../../lib/collectionUtils'
import TurndownService from 'turndown';
const turndownService = new TurndownService()
turndownService.remove('style') // Make sure we don't add the content of style tags to the markdown

import markdownIt from 'markdown-it'
import markdownItMathjax from './markdown-mathjax.js'
import markdownItContainer from 'markdown-it-container'
const mdi = markdownIt({linkify: true})
mdi.use(markdownItMathjax())
mdi.use(markdownItContainer, 'spoiler')
import { addCallback } from 'meteor/vulcan:core';
import { mjpage }  from 'mathjax-node-page'

function mjPagePromise(html, beforeSerializationCallback) {
  // Takes in HTML and replaces LaTeX with CommonHTML snippets
  // https://github.com/pkra/mathjax-node-page
  return new Promise((resolve, reject) => {
    mjpage(html, {}, {html: true, css: true}, resolve)
      .on('beforeSerialization', beforeSerializationCallback);
  })
}

export async function draftJSToHtmlWithLatex(draftJS) {
  const draftJSWithLatex = await Utils.preProcessLatex(draftJS)
  return draftToHTML(convertFromRaw(draftJSWithLatex))
}

export function htmlToMarkdown(html) {
  return turndownService.turndown(html)
}

export function markdownToHtml(markdown) {
  return mdi.render(markdown)
}

export async function markdownToHtmlWithLatex(markdown) {
  const html = markdownToHtml(markdown)
  return await mjPagePromise(html, Utils.trimEmptyLatexParagraphs)
}

async function dataToHTML(data, type, sanitize = false) {
  switch (type) {
    case "html":
      return sanitize ? Utils.sanitize(data) : data
    case "draftJS":
      return await draftJSToHtmlWithLatex(data)
    case "markdown":
      return await markdownToHtmlWithLatex(data)
  }
}

export function dataToMarkdown(data, type) {
  if (!data) return ""
  switch (type) {
    case "markdown": {
      return data
    }
    case "html": {
      return htmlToMarkdown(data)
    }
    case "draftJS": {
      try {
        const contentState = convertFromRaw(data);
        const html = draftToHTML(contentState)
        return htmlToMarkdown(html)
      } catch(e) {
        // eslint-disable-next-line no-console
        console.error(e)
      }
      return ""
    }
  }
}

export async function dataToWordCount(data, type) {
  const markdown = dataToMarkdown(data, type) || ""
  return markdown.split(" ").length
}

function getInitialVersion(document) {
  if (document.draft) {
    return '0.1.0'
  } else {
    return '1.0.0'
  }
}

async function getNextVersion(documentId, updateType = 'minor') {
  const lastRevision = await Revisions.findOne({documentId: documentId}, {sort: {editedAt: -1}}) || {}
  const { major, minor, patch } = extractVersionsFromSemver(lastRevision.version)
  switch (updateType) {
    case "patch":
      return `${major}.${minor}.${patch + 1}`
    case "minor":
      return `${major}.${minor + 1}.0`
    case "major":
      return `${major+1}.0.0`
    default:
      throw new Error("Invalid updateType, must be one of 'patch', 'minor' or 'major'")
  }
}

ensureIndex(Revisions, {documentId: 1, version: 1, fieldName: 1, editedAt: 1})

export function addEditableCallbacks({collection, options = {}}) {
  const {
    fieldName = "contents",
    // deactivateNewCallback // Because of Meteor shenannigans we don't have access to the full user object when a new user is created, and this creates
    // // bugs when we register callbacks that trigger on new user creation. So we allow the deactivation of the new callbacks.
  } = options

  const { typeName } = collection.options

  async function editorSerializationNew (doc, { currentUser }) {
    if (doc[fieldName] && doc[fieldName].originalContents) {
      if (!currentUser) { throw Error("Can't create document without current user") }
      const { data, type } = doc[fieldName].originalContents
      const html = await dataToHTML(data, type, !currentUser.isAdmin)
      const wordCount = await dataToWordCount(data, type)
      const version = getInitialVersion(doc)
      const userId = currentUser._id
      const editedAt = new Date()
      return {...doc, [fieldName]: {...doc[fieldName], html, version, userId, editedAt, wordCount}}
    }
    return doc
  }

  addCallback(`${typeName.toLowerCase()}.create.before`, editorSerializationNew);

  async function editorSerializationEdit (docData, { document, currentUser }) {
    if (docData[fieldName] && docData[fieldName].originalContents) {
      if (!currentUser) { throw Error("Can't create document without current user") }
      const { data, type } = docData[fieldName].originalContents
      const html = await dataToHTML(data, type, !currentUser.isAdmin)
      const wordCount = await dataToWordCount(data, type)
      const defaultUpdateType = (document.draft && !docData.draft) ? 'major' : 'minor'
      const version = await getNextVersion(document._id, docData[fieldName].updateType || defaultUpdateType)
      const userId = currentUser._id
      const editedAt = new Date()
      return {...docData, [fieldName]: {...docData[fieldName], html, version, userId, editedAt, wordCount}}
    }
    return docData
  }

  addCallback(`${typeName.toLowerCase()}.update.before`, editorSerializationEdit);

  async function editorSerializationCreateRevision(doc) {
    if (doc[fieldName] && doc[fieldName].originalContents) {
      Revisions.insert({
        ...doc[fieldName],
        documentId: doc._id,
        fieldName
      })
    }
    return doc
  }

  addCallback(`${typeName.toLowerCase()}.create.after`, editorSerializationCreateRevision)
  addCallback(`${typeName.toLowerCase()}.update.after`, editorSerializationCreateRevision)
}
<|endoftext|>


<commit_before>'use strict';

/**
 * themelist helper, can be used to display lists of themes based on the config theme array
 */

const config = require('config');
const view = require('../../../lib/view.js');
const twigUtils = require('../utils');

module.exports = function (Twig) {
	return {
		type: 'themelist',
		regex: /^themelist\s*([\S\s]+?)?$/,
		next: [],
		open: true,
		compile (token) {
			const data = (typeof token.match[1] !== 'undefined') ? token.match[1] : '';

			token.variantStack = Twig.expression.compile.apply(this, [{
				type: Twig.expression.type.expression,
				value: data.trim()
			}]).stack;

			delete token.match;
			return token;
		},
		parse (token, context, chain) {
			try {
				const data = Twig.expression.parse.apply(this, [token.variantStack, context]) ? Twig.expression.parse.apply(this, [token.variantStack, context]) : {};
				const include = data.include ? data.include : '';
				const exclude = data.exclude ? data.exclude : '';

				const views = view.getViews(config.get('nitro.basePath') + config.get('nitro.viewDirectory'));
				const markup = ['
'];

				let filteredViews = views;

				if (include !== '') {
					const includeArray = include.split(',');
					filteredViews = views.filter((viewItem) => {
						return includeArray.some((includeString) => {
							return viewItem.url.indexOf(includeString) >= 0;
						});
					});
				}

				if (exclude !== '') {
					const excludeArray = exclude.split(',');
					filteredViews = views.filter((viewItem) => {
						return excludeArray.every((excludeString) => {
							return viewItem.url.indexOf(excludeString) === -1;
						});
					});
				}

				filteredViews.forEach((viewItem) => {
					markup.push(`<li><a href="/${viewItem.url}">${viewItem.name}</a></li>`);
				});

				if (filteredViews.length === 0) {
					markup.push('
For this include / exclude term, no pages where found
');
				}

				// return the markup
				return {
					chain,
					output: markup.join('')
				};

			} catch (e) {
				return {
					chain,
					output: twigUtils.logAndRenderError(e)
				};
			}
		}
	};
};
<commit_msg>feat(project): remove obsolete themelist helper for twig templating #172<commit_after><|endoftext|>


<commit_before>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { settings } from 'carbon-components';
import cx from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';

const { prefix } = settings;

const HeaderSideNavItems = ({
  className: customClassName,
  children,
  hasDivider,
}) => {
  const className = cx({
    [`${prefix}--side-nav__header-navigation`]: true,
    [`${prefix}--side-nav__header-divider`]: hasDivider,
    customClassName,
  });
  return
{children}
;
};

HeaderSideNavItems.propTypes = {
  /**
   * Optionally provide a custom class name that is applied to the underlying
   * button
   */
  className: PropTypes.string,

  /**
   * Optionally specify if container will have a bottom divider to differentiate
   * between original sidenav items and header menu items. False by default.
   */
  hasDivider: PropTypes.bool,
};

HeaderSideNavItems.defaultProps = {
  hasDivider: false,
};

export default HeaderSideNavItems;
<commit_msg>fix(ui-shell): allow custom classes on HeaderSideNavItems (#5275)<commit_after>/**
 * Copyright IBM Corp. 2016, 2018
 *
 * This source code is licensed under the Apache-2.0 license found in the
 * LICENSE file in the root directory of this source tree.
 */

import { settings } from 'carbon-components';
import cx from 'classnames';
import React from 'react';
import PropTypes from 'prop-types';

const { prefix } = settings;

const HeaderSideNavItems = ({
  className: customClassName,
  children,
  hasDivider,
}) => {
  const className = cx(
    {
      [`${prefix}--side-nav__header-navigation`]: true,
      [`${prefix}--side-nav__header-divider`]: hasDivider,
    },
    customClassName
  );
  return
{children}
;
};

HeaderSideNavItems.propTypes = {
  /**
   * Optionally provide a custom class name that is applied to the underlying
   * button
   */
  className: PropTypes.string,

  /**
   * Optionally specify if container will have a bottom divider to differentiate
   * between original sidenav items and header menu items. False by default.
   */
  hasDivider: PropTypes.bool,
};

HeaderSideNavItems.defaultProps = {
  hasDivider: false,
};

export default HeaderSideNavItems;
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

import Button from '../../Button'
import StyledFormControl from './StyledFormControl'
import {stringToDuration, numbersToTimeFormat} from '../utils'

const TimeEdit = props => {
  const hours = props.value ? props.value.hourOfDay : null
  const minutes = props.value ? props.value.minuteOfHour : null

  const timeString = numbersToTimeFormat(hours, minutes)

  const handleChange = e => {
    props.onChange(stringToDuration(e.target.value))
  }

  const clearInput = () => {
    props.onChange(null)
  }

  return (
    <StyledFormControl readOnly={props.readOnly}>
      <input
        type="time"
        value={timeString}
        onChange={handleChange}
        name={props.name}
        id={props.id}
        readOnly={props.readOnly}
      />
      { !props.readOnly
        && <Button
          icon="times"
          look="ball"
          onClick={clearInput}
          tabIndex={-1}
        />
      }
    </StyledFormControl>
  )
}

TimeEdit.propTypes = {
  onChange: PropTypes.func.isRequired,
  value: PropTypes.shape({
    hourOfDay: PropTypes.number,
    minuteOfHour: PropTypes.number,
    secondOfMinute: PropTypes.number,
    millisOfSecond: PropTypes.number
  }),
  name: PropTypes.string,
  id: PropTypes.string,
  readOnly: PropTypes.bool
}

export default TimeEdit
<commit_msg>fix(tocco-ui): display clear button on TimeEdit if reasonable<commit_after>import React from 'react'
import PropTypes from 'prop-types'

import Button from '../../Button'
import StyledFormControl from './StyledFormControl'
import {stringToDuration, numbersToTimeFormat} from '../utils'

const TimeEdit = props => {
  const hours = props.value ? props.value.hourOfDay : null
  const minutes = props.value ? props.value.minuteOfHour : null

  const timeString = numbersToTimeFormat(hours, minutes)

  const handleChange = e => {
    props.onChange(stringToDuration(e.target.value))
  }

  const clearInput = () => {
    props.onChange(null)
  }

  const isFirefox = !!window.sidebar

  const showClearButton = props.value && !props.readOnly && !isFirefox

  return (
    <StyledFormControl readOnly={props.readOnly}>
      <input
        type="time"
        value={timeString}
        onChange={handleChange}
        name={props.name}
        id={props.id}
        readOnly={props.readOnly}
      />
      {
        showClearButton && <Button
          icon="times"
          look="ball"
          onClick={clearInput}
          tabIndex={-1}
        />
      }
    </StyledFormControl>
  )
}

TimeEdit.propTypes = {
  onChange: PropTypes.func.isRequired,
  value: PropTypes.shape({
    hourOfDay: PropTypes.number,
    minuteOfHour: PropTypes.number,
    secondOfMinute: PropTypes.number,
    millisOfSecond: PropTypes.number
  }),
  name: PropTypes.string,
  id: PropTypes.string,
  readOnly: PropTypes.bool
}

export default TimeEdit
<|endoftext|>


<commit_before>/* eslint-disable no-console */
import { findKey } from 'lodash-es';

const titleCSS = 'color:red; font-size:20px; font-weight: bold;';
const descCSS = color => `font-size: 16px; color:${color};`;
const descDefaultCSS = descCSS('#000');
const descDefaultItalicCSS = descCSS('#000') + 'font-style:italic;';
const descKeywordCSS = descCSS('#008') + 'font-weight:600;';
const descStringCSS = descCSS('#080');
const descCommentCSS = descCSS('#808080') + 'font-style:italic;';
const descNewLine = 'font-size: 1px; margin-right: 100%;';

const moduleToImportPath = {
  annotations: 'modules/annotations',
  more: 'highcharts-more',
  threeD: 'highcharts-3d',
  bullet: 'modules/bullet',
  funnel: 'modules/funnel',
  histogram: 'modules/histogram-bellcurve',
  pareto: 'modules/pareto',
  sankey: 'modules/sankey',
  solidgauge: 'modules/solid-gauge',
  streamgraph: 'modules/streamgraph',
  sunburst: 'modules/sunburst',
  tilemap: 'modules/tilemap',
  treemap: 'modules/treemap',
  variablepie: 'modules/variable-pie',
  variwide: 'modules/variwide',
  vector: 'modules/vector',
  windbarb: 'modules/windbarb',
  xrange: 'modules/xrange'
};

const moduleToVarName = {
  annotations: 'addAnnotations',
  more: 'addHighchartsMore',
  threeD: 'addHighcharts3DModule',
  bullet: 'addBulletModule',
  funnel: 'addFunnelModule',
  histogram: 'addHistogramBellCurveModule',
  pareto: 'addParetoModule',
  sankey: 'addSankeyModule',
  solidgauge: 'addSolidGaugeModule',
  streamgraph: 'addStreamGraphModule',
  sunburst: 'addSunburstModule',
  tilemap: 'addTilemapModule',
  treemap: 'addTreemapModule',
  variablepie: 'addVariablePieModule',
  variwide: 'addVariwideModule',
  vector: 'addVectorModule',
  windbarb: 'addWindBarbModule',
  xrange: 'addXRangeModule'
};

const moduleToSeriesTypes = {
  annotations: ['annotations'],
  more: ['arearange', 'areasplinerange', 'boxplot', 'bubble', 'columnrange', 'errorbar', 'polygon', 'waterfall', 'gauge'],
  threeD: ['scatter3d'],
  bullet: ['bullet'],
  funnel: ['funnel', 'pyramid'],
  histogram: ['histogram', 'bellcurve'],
  pareto: ['pareto'],
  sankey: ['sankey'],
  solidgauge: ['solidgauge'],
  streamgraph: ['streamgraph'],
  sunburst: ['sunburst'],
  tilemap: ['tilemap'],
  treemap: ['treemap'],
  variablepie: ['variablepie'],
  variwide: ['variwide'],
  vector: ['vector'],
  windbarb: ['windbarb'],
  xrange: ['xrange']
};

const findModule = seriesType => {
  return findKey(moduleToSeriesTypes, seriesTypes => seriesTypes.indexOf(seriesType) !== -1)
}

const logDetailedErrorMessage = (warning, module) => {
  const importPath = moduleToImportPath[module];
  const varName = moduleToVarName[module];

  console.group("React JSX Highcharts error");
  console.log(`%c${warning}`, titleCSS);
  console.log('More information: https://github.com/whawker/react-jsx-highcharts/wiki/Highcharts-error-%2317');
  console.log(
    `You likely need to import the additional module, try adding
    %c
    %c %cimport %cHighcharts %cfrom %c'highcharts'%c;
    %c %cimport %c${varName} %cfrom %c'highcharts/${importPath}'%c;
    %c
    %c %c// After imports, but before component - apply additional functionality from module to Highcharts
    %c %c${varName}%c(Highcharts);`.replace(/^ +/gm, ''),
    descNewLine,
    descNewLine, descKeywordCSS, descDefaultCSS, descKeywordCSS, descStringCSS, descDefaultCSS,
    descNewLine, descKeywordCSS, descDefaultCSS, descKeywordCSS, descStringCSS, descDefaultCSS,
    descNewLine,
    descNewLine, descCommentCSS,
    descNewLine, descDefaultItalicCSS, descDefaultCSS
  );
  console.groupEnd();
}

export const logSeriesErrorMessage = seriesType => {
  if (process.env.NODE_ENV === 'development') {
    const warning = `This series type "${seriesType}" requires an additional Highcharts module`;
    const module = findModule(seriesType);

    if (!module) {
      console.warn(`${warning}, or is invalid.`);
      return
    }

    logDetailedErrorMessage(warning, module);
  }
}

export const logModuleErrorMessage = (componentName, moduleName) => {
  if (process.env.NODE_ENV === 'development') {
    const warning = `This component "${componentName}" requires an additional Highcharts module`;
    const module = findModule(moduleName);

    if (!module) {
      console.warn(`${warning}, or is invalid.`);
      return
    }

    logDetailedErrorMessage(warning, module);
  }
}

export const logZAxisErrorMessage = () => {
  if (process.env.NODE_ENV === 'development') {
    logDetailedErrorMessage('This axis type "ZAxis" requires an additional Highcharts module', 'threeD');
  }
}
<commit_msg>Rename moduleToSeriesTypes to moduleToFeatureMap<commit_after>/* eslint-disable no-console */
import { findKey } from 'lodash-es';

const titleCSS = 'color:red; font-size:20px; font-weight: bold;';
const descCSS = color => `font-size: 16px; color:${color};`;
const descDefaultCSS = descCSS('#000');
const descDefaultItalicCSS = descCSS('#000') + 'font-style:italic;';
const descKeywordCSS = descCSS('#008') + 'font-weight:600;';
const descStringCSS = descCSS('#080');
const descCommentCSS = descCSS('#808080') + 'font-style:italic;';
const descNewLine = 'font-size: 1px; margin-right: 100%;';

const moduleToImportPath = {
  annotations: 'modules/annotations',
  more: 'highcharts-more',
  threeD: 'highcharts-3d',
  bullet: 'modules/bullet',
  funnel: 'modules/funnel',
  histogram: 'modules/histogram-bellcurve',
  pareto: 'modules/pareto',
  sankey: 'modules/sankey',
  solidgauge: 'modules/solid-gauge',
  streamgraph: 'modules/streamgraph',
  sunburst: 'modules/sunburst',
  tilemap: 'modules/tilemap',
  treemap: 'modules/treemap',
  variablepie: 'modules/variable-pie',
  variwide: 'modules/variwide',
  vector: 'modules/vector',
  windbarb: 'modules/windbarb',
  xrange: 'modules/xrange'
};

const moduleToVarName = {
  annotations: 'addAnnotations',
  more: 'addHighchartsMore',
  threeD: 'addHighcharts3DModule',
  bullet: 'addBulletModule',
  funnel: 'addFunnelModule',
  histogram: 'addHistogramBellCurveModule',
  pareto: 'addParetoModule',
  sankey: 'addSankeyModule',
  solidgauge: 'addSolidGaugeModule',
  streamgraph: 'addStreamGraphModule',
  sunburst: 'addSunburstModule',
  tilemap: 'addTilemapModule',
  treemap: 'addTreemapModule',
  variablepie: 'addVariablePieModule',
  variwide: 'addVariwideModule',
  vector: 'addVectorModule',
  windbarb: 'addWindBarbModule',
  xrange: 'addXRangeModule'
};

const moduleToFeatureMap = {
  annotations: ['annotations'],
  more: ['arearange', 'areasplinerange', 'boxplot', 'bubble', 'columnrange', 'errorbar', 'polygon', 'waterfall', 'gauge'],
  threeD: ['scatter3d'],
  bullet: ['bullet'],
  funnel: ['funnel', 'pyramid'],
  histogram: ['histogram', 'bellcurve'],
  pareto: ['pareto'],
  sankey: ['sankey'],
  solidgauge: ['solidgauge'],
  streamgraph: ['streamgraph'],
  sunburst: ['sunburst'],
  tilemap: ['tilemap'],
  treemap: ['treemap'],
  variablepie: ['variablepie'],
  variwide: ['variwide'],
  vector: ['vector'],
  windbarb: ['windbarb'],
  xrange: ['xrange']
};

const findModule = feature => {
  return findKey(moduleToFeatureMap, features => features.indexOf(feature) !== -1)
}

const logDetailedErrorMessage = (warning, module) => {
  const importPath = moduleToImportPath[module];
  const varName = moduleToVarName[module];

  console.group("React JSX Highcharts error");
  console.log(`%c${warning}`, titleCSS);
  console.log('More information: https://github.com/whawker/react-jsx-highcharts/wiki/Highcharts-error-%2317');
  console.log(
    `You likely need to import the additional module, try adding
    %c
    %c %cimport %cHighcharts %cfrom %c'highcharts'%c;
    %c %cimport %c${varName} %cfrom %c'highcharts/${importPath}'%c;
    %c
    %c %c// After imports, but before component - apply additional functionality from module to Highcharts
    %c %c${varName}%c(Highcharts);`.replace(/^ +/gm, ''),
    descNewLine,
    descNewLine, descKeywordCSS, descDefaultCSS, descKeywordCSS, descStringCSS, descDefaultCSS,
    descNewLine, descKeywordCSS, descDefaultCSS, descKeywordCSS, descStringCSS, descDefaultCSS,
    descNewLine,
    descNewLine, descCommentCSS,
    descNewLine, descDefaultItalicCSS, descDefaultCSS
  );
  console.groupEnd();
}

export const logSeriesErrorMessage = seriesType => {
  if (process.env.NODE_ENV === 'development') {
    const warning = `This series type "${seriesType}" requires an additional Highcharts module`;
    const module = findModule(seriesType);

    if (!module) {
      console.warn(`${warning}, or is invalid.`);
      return
    }

    logDetailedErrorMessage(warning, module);
  }
}

export const logModuleErrorMessage = (componentName, moduleName) => {
  if (process.env.NODE_ENV === 'development') {
    const warning = `This component "${componentName}" requires an additional Highcharts module`;
    const module = findModule(moduleName);

    if (!module) {
      console.warn(`${warning}, or is invalid.`);
      return
    }

    logDetailedErrorMessage(warning, module);
  }
}

export const logZAxisErrorMessage = () => {
  if (process.env.NODE_ENV === 'development') {
    logDetailedErrorMessage('This axis type "ZAxis" requires an additional Highcharts module', 'threeD');
  }
}
<|endoftext|>


<commit_before>var Lang = A.Lang,
	isString = Lang.isString,

	RESIZE_IFRAME = 'resizeiframe',

	getClassName = A.getClassName,

	HEIGHT = 'height',
	HIDDEN = 'hidden',
	NO = 'no',
	SCROLLING = 'scrolling',
	WIDTH = 'width',

	CSS_RESIZE_IFRAME_MONITORED_HEIGHT = getClassName(RESIZE_IFRAME, 'monitored', HEIGHT);

ResizeIframe = A.Component.create(
	{
		NAME: RESIZE_IFRAME,
		NS: RESIZE_IFRAME,

		EXTENDS: A.Plugin.Base,

		ATTRS: {
			height: {
				value: 0
			},
			monitorHeight: {
				value: true
			},
			width: {
				value: null
			}
		},

		prototype: {
			initializer: function() {
				var instance = this;

				var frame = instance.get('host');

				instance.node = frame;
				instance._iframeEl = frame.getDOM();

				instance.bindUI();
				instance.syncUI();
			},

			bindUI: function() {
				var instance = this;

				instance.after('heightChange', instance._afterHeightChange);
				instance.after('monitorHeightChange', instance._afterMonitorHeightChange);
				instance.after('widthChange', instance._afterWidthChange);
			},

			syncUI: function() {
				var instance = this;

				instance._uiSetMonitorHeight(instance.get('monitorHeight'));
			},

			destructor: function() {
				var instance = this;

				instance._uiSetMonitorHeight(false);
			},

			pauseMonitor: function() {
				var instance = this;

				instance._clearInterval();
			},

			restartMonitor: function() {
				var instance = this;

				if (instance.get('monitorHeight')) {
					instance._setInterval();
				}
			},

			_afterHeightChange: function(event) {
				var instance = this;

				instance.set('monitorHeight', false);

				instance._uiSetHeight(event.newVal);
			},

			_afterMonitorHeightChange: function(event) {
				var instance = this;

				instance._uiSetMonitorHeight(event.newVal);
			},

			_afterWidthChange: function(event) {
				var instance = this;

				instance._uiSetWidth(event.newVal);
			},

			_clearInterval: function() {
				var instance = this;

				var iframeDoc = instance._iframeDoc;

				if (iframeDoc) {
					var docEl = iframeDoc.documentElement;

					if (docEl) {
						docEl.style.overflowY = '';
					}
				}

				if (instance._intervalId) {
					A.clearInterval(instance._intervalId);

					instance._intervalId = null;
				}
			},

			_getQuirksHeight: function(iframeWin) {
				var instance = this;

				var contentHeight = 0;

				var iframeDoc = iframeWin.document;
				var docEl = iframeDoc && iframeDoc.documentElement;
				var iframeBody = iframeDoc && iframeDoc.body;

				var viewPortHeight = 0;

				if (iframeWin.innerHeight) {
					viewPortHeight = iframeWin.innerHeight;
				}
				else if (docEl && docEl.clientHeight) {
					viewPortHeight = docEl.clientHeight;
				}
				else if (iframeBody) {
					viewPortHeight = iframeBody.clientHeight;
				}

				if (iframeDoc) {
					var docClientHeight;
					var docScrollHeight;
					var docOffsetHeight = (iframeBody && iframeBody.offsetHeight);

					if (docEl) {
						docClientHeight = docEl.clientHeight;
						docScrollHeight = docEl.scrollHeight;
						docOffsetHeight = docEl.offsetHeight;
					}

					if (docClientHeight != docOffsetHeight && iframeBody) {
						docOffsetHeight = iframeBody.offsetHeight;
						docScrollHeight = iframeBody.scrollHeight;
					}

					var compareNum;

					if (docScrollHeight > viewPortHeight) {
						compareNum = Math.max;
					}
					else {
						compareNum = Math.min;
					}

					contentHeight = compareNum(docScrollHeight, docOffsetHeight);
				}

				return contentHeight;
			},

			_onResize: function() {
				var instance = this;

				instance._iframeDoc = null;

				var newHeight = instance._iframeHeight;
				var iframeWin = instance._iframeEl.contentWindow;

				var iframeDoc;

				try {
					iframeDoc = iframeWin.document;

					instance._iframeDoc = iframeDoc;
				}
				catch (e) {
				}

				if (iframeDoc) {
					var docEl = iframeDoc.documentElement;
					var iframeBody = iframeDoc.body;

					if (docEl) {
						docEl.style.overflowY = HIDDEN;
					}

					var docOffsetHeight = (iframeBody && iframeBody.offsetHeight) || 0;

					var standardsMode = (iframeDoc.compatMode == 'CSS1Compat');

					if (standardsMode && docOffsetHeight) {
						newHeight = docOffsetHeight;
					}
					else {
						newHeight = instance._getQuirksHeight(iframeWin) || instance._iframeHeight;
					}

					instance._uiSetHeight(newHeight);
				}
				else {
					instance._clearInterval();
				}
			},

			_setInterval: function(event) {
				var instance = this;

				if (!instance._intervalId) {
					instance._intervalId = A.setInterval(instance._onResize, 100, instance);
				}
			},

			_uiSetHeight: function(value) {
				var instance = this;

				if (instance._iframeHeight != value) {
					instance._iframeHeight = value;

					instance.node.setStyle(HEIGHT, value);
				}
			},

			_uiSetMonitorHeight: function(monitorHeight) {
				var instance = this;

				var iframe = instance.node;

				if (monitorHeight) {
					instance._setInterval();

					instance._loadHandle = iframe.on('load', instance._setInterval, instance);

					iframe.addClass(CSS_RESIZE_IFRAME_MONITORED_HEIGHT);
				}
				else {
					instance._clearInterval();

					if (instance._loadHandle) {
						instance._loadHandle.detach();
					}

					iframe.removeClass(CSS_RESIZE_IFRAME_MONITORED_HEIGHT);
				}
			},

			_uiSetWidth: function(value) {
				var instance = this;

				instance.node.setStyle(WIDTH, value);
			},

			_iframeHeight: 0
		}
	}
);

A.Plugin.ResizeIframe = ResizeIframe;<commit_msg>AUI-409 - Moving height methods to static impls (makes it easier to backport as well as use as a general utility)<commit_after>var Lang = A.Lang,
	isString = Lang.isString,

	RESIZE_IFRAME = 'resizeiframe',

	getClassName = A.getClassName,

	HEIGHT = 'height',
	HIDDEN = 'hidden',
	NO = 'no',
	SCROLLING = 'scrolling',
	WIDTH = 'width',

	CSS_RESIZE_IFRAME_MONITORED_HEIGHT = getClassName(RESIZE_IFRAME, 'monitored', HEIGHT);

ResizeIframe = A.Component.create(
	{
		NAME: RESIZE_IFRAME,
		NS: RESIZE_IFRAME,

		EXTENDS: A.Plugin.Base,

		ATTRS: {
			height: {
				value: 0
			},
			monitorHeight: {
				value: true
			},
			width: {
				value: null
			}
		},

		prototype: {
			initializer: function() {
				var instance = this;

				var frame = instance.get('host');

				instance.node = frame;
				instance._iframeEl = frame.getDOM();

				instance.bindUI();
				instance.syncUI();
			},

			bindUI: function() {
				var instance = this;

				instance.after('heightChange', instance._afterHeightChange);
				instance.after('monitorHeightChange', instance._afterMonitorHeightChange);
				instance.after('widthChange', instance._afterWidthChange);
			},

			syncUI: function() {
				var instance = this;

				instance._uiSetMonitorHeight(instance.get('monitorHeight'));
			},

			destructor: function() {
				var instance = this;

				instance._uiSetMonitorHeight(false);
			},

			pauseMonitor: function() {
				var instance = this;

				instance._clearInterval();
			},

			restartMonitor: function() {
				var instance = this;

				if (instance.get('monitorHeight')) {
					instance._setInterval();
				}
			},

			_afterHeightChange: function(event) {
				var instance = this;

				instance.set('monitorHeight', false);

				instance._uiSetHeight(event.newVal);
			},

			_afterMonitorHeightChange: function(event) {
				var instance = this;

				instance._uiSetMonitorHeight(event.newVal);
			},

			_afterWidthChange: function(event) {
				var instance = this;

				instance._uiSetWidth(event.newVal);
			},

			_clearInterval: function() {
				var instance = this;

				var iframeDoc = instance._iframeDoc;

				if (iframeDoc) {
					var docEl = iframeDoc.documentElement;

					if (docEl) {
						docEl.style.overflowY = '';
					}
				}

				if (instance._intervalId) {
					A.clearInterval(instance._intervalId);

					instance._intervalId = null;
				}
			},

			_onResize: function() {
				var instance = this;

				instance._iframeDoc = null;

				var newHeight = instance._iframeHeight;
				var iframeWin = instance._iframeEl.contentWindow;

				var iframeDoc;

				try {
					iframeDoc = iframeWin.document;

					instance._iframeDoc = iframeDoc;
				}
				catch (e) {
				}

				if (iframeDoc) {
					newHeight = ResizeIframe._getContentHeight(iframeWin, iframeDoc, instance._iframeHeight);

					instance._uiSetHeight(newHeight);
				}
				else {
					instance._clearInterval();
				}
			},

			_setInterval: function(event) {
				var instance = this;

				if (!instance._intervalId) {
					instance._intervalId = A.setInterval(instance._onResize, 100, instance);
				}
			},

			_uiSetHeight: function(value) {
				var instance = this;

				if (instance._iframeHeight != value) {
					instance._iframeHeight = value;

					instance.node.setStyle(HEIGHT, value);
				}
			},

			_uiSetMonitorHeight: function(monitorHeight) {
				var instance = this;

				var iframe = instance.node;

				if (monitorHeight) {
					instance._setInterval();

					instance._loadHandle = iframe.on('load', instance._setInterval, instance);

					iframe.addClass(CSS_RESIZE_IFRAME_MONITORED_HEIGHT);
				}
				else {
					instance._clearInterval();

					if (instance._loadHandle) {
						instance._loadHandle.detach();
					}

					iframe.removeClass(CSS_RESIZE_IFRAME_MONITORED_HEIGHT);
				}
			},

			_uiSetWidth: function(value) {
				var instance = this;

				instance.node.setStyle(WIDTH, value);
			},

			_iframeHeight: 0
		}
	}
);

A.mix(
	ResizeIframe,
	{
		getContentHeight: function(iframeWin) {
			var contentHeight = null;

			try {
				var iframeDoc;

				if (iframeWin.nodeName && iframeWin.nodeName.toLowerCase() == 'iframe') {
					iframeWin = iframeWin.contentWindow;
				}
				else if (A.instanceOf(iframeWin, A.Node)) {
					iframeWin = iframeWin.getDOM().contentWindow;
				}

				iframeDoc = iframeWin.document;

				contentHeight = ResizeIframe._getContentHeight(iframeWin, iframeDoc);
			}
			catch (e) {
			}

			return contentHeight;
		},

		_getContentHeight: function(iframeWin, iframeDoc, fallbackHeight) {
			var contentHeight = null;

			if (iframeDoc) {
				var docEl = iframeDoc.documentElement;
				var iframeBody = iframeDoc.body;

				if (docEl) {
					docEl.style.overflowY = HIDDEN;
				}

				var docOffsetHeight = (iframeBody && iframeBody.offsetHeight) || 0;

				var standardsMode = (iframeDoc.compatMode == 'CSS1Compat');

				if (standardsMode && docOffsetHeight) {
					contentHeight = docOffsetHeight;
				}
				else {
					contentHeight = ResizeIframe._getQuirksHeight(iframeWin) || fallbackHeight;
				}
			}

			return contentHeight;
		},

		_getQuirksHeight: function(iframeWin) {
			var contentHeight = 0;

			var iframeDoc = iframeWin.document;
			var docEl = iframeDoc && iframeDoc.documentElement;
			var iframeBody = iframeDoc && iframeDoc.body;

			var viewPortHeight = 0;

			if (iframeWin.innerHeight) {
				viewPortHeight = iframeWin.innerHeight;
			}
			else if (docEl && docEl.clientHeight) {
				viewPortHeight = docEl.clientHeight;
			}
			else if (iframeBody) {
				viewPortHeight = iframeBody.clientHeight;
			}

			if (iframeDoc) {
				var docClientHeight;
				var docScrollHeight;
				var docOffsetHeight = (iframeBody && iframeBody.offsetHeight);

				if (docEl) {
					docClientHeight = docEl.clientHeight;
					docScrollHeight = docEl.scrollHeight;
					docOffsetHeight = docEl.offsetHeight;
				}

				if (docClientHeight != docOffsetHeight && iframeBody) {
					docOffsetHeight = iframeBody.offsetHeight;
					docScrollHeight = iframeBody.scrollHeight;
				}

				var compareNum;

				if (docScrollHeight > viewPortHeight) {
					compareNum = Math.max;
				}
				else {
					compareNum = Math.min;
				}

				contentHeight = compareNum(docScrollHeight, docOffsetHeight);
			}

			return contentHeight;
		}
	}
);

A.Plugin.ResizeIframe = ResizeIframe;<|endoftext|>