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

/**
 * Base class of ES6 React classes, modeled as a polymorphic class whose type
 * parameters are DefaultProps, Props, State.
 */
declare class React$Component<DefaultProps, Props, State> {
  // fields

  static defaultProps: $Abstract<DefaultProps>;
  props: Props;
  state: $Abstract<State>;

  // action methods

  // TODO: partialState could be a function as well
  setState(partialState: $Shape<State>, callback?: () => void): void;

  forceUpdate(callback?: () => void): void;

  // lifecycle methods

  render(): ?React$Element<any>;
  componentWillMount(): void;
  componentDidMount(component?: any): void;
  componentWillReceiveProps(nextProps: Props, nextContext?: any): void;
  shouldComponentUpdate(nextProps: Props, nextState: State, nextContext: any): boolean;
  componentWillUpdate(nextProps: Props, nextState: State, nextContext: any): void;
  componentDidUpdate(nextProps: Props, nextState: State, nextContext: any, component: any): void;
  componentWillUnmount(): void;

  // long tail of other stuff not modeled very well

  refs: any;
  context: any;
  getChildContext(): any;
  static displayName: string;
  static childContextTypes: any;
  static contextTypes: any;
  static propTypes: $Subtype<{[_: $Keys<Props>]: any}>; //object whose keys are in PropTypes
}

declare class React$PureComponent<DefaultProps, Props, State> extends React$Component<DefaultProps, Props, State> {
  // TODO: Due to bugs in Flow's handling of React.createClass, some fields
  // already declared in the base class need to be redeclared below. Ideally
  // they should simply be inherited.

  static defaultProps: $Abstract<DefaultProps>;
  props: Props;
  state: $Abstract<State>;
}

/**
 * Base class of legacy React classes, which extends the base class of ES6 React
 * classes and supports additional methods.
 */
declare class LegacyReactComponent<DefaultProps, Props, State> extends React$Component<DefaultProps, Props, State> {
  // additional methods

  replaceState(state: State, callback?: () => void): void;

  isMounted(): bool;

  // TODO: Due to bugs in Flow's handling of React.createClass, some fields
  // already declared in the base class need to be redeclared below. Ideally
  // they should simply be inherited.

  static defaultProps: DefaultProps;
  props: Props;
  state: State;
}

/**
 * Type of a React class (not to be confused with the type of instances of a
 * React class, which is the React class itself). A React class is any subclass
 * of React$Component. We make the type of a React class parametric over Config,
 * which is derived from some of the type parameters (DefaultProps, Props) of
 * React$Component, abstracting away others (State); whereas a React$Component
 * type is useful for checking the definition of a React class, a ReactClass
 * type (and the corresponding React$Element type, see below) is useful for
 * checking the uses of a React class. The required constraints are set up using
 * a "helper" type alias, that takes an additional type parameter C representing
 * the React class, which is then abstracted with an existential type (*). The *
 * can be thought of as an "auto" instruction to the typechecker, telling it to
 * fill in the type from context.
 */
type ReactClass<Config> = _ReactClass<*, *, Config, *>;
type _ReactClass<DefaultProps, Props, Config: $Diff<Props, DefaultProps>, C: React$Component<DefaultProps, Props, any>> = Class<C>;

// TODO: DefaultProps and Props are needed to type some introspection APIs
// below, but in general, Config does not carry enough information to recover
// them faithfully. For now, we trade off that additional precision for overall
// simplicity of the model. In the future, we may provide more powerful
// introspection features in types, at which point Config would carry enough
// information to faithfully recover DefaultProps and Props.
type $PropsOf<Config> = any
type $DefaultPropsOf<Config> = any

/**
 * Type of a React element. React elements are commonly created using JSX
 * literals, which desugar to React.createElement calls (see below). The type
 * parameterization of React$Element mimics that of ReactClass (see above).
 */
declare class React$Element<Config> {
  type: ReactClass<Config>;
  props: $PropsOf<Config>;
  key: ?string;
  ref: any;
}

type ReactPropsCheckType = (
  props: any,
  propName: string,
  componentName: string,
  href?: string) => ?Error;

type ReactPropsChainableTypeChecker = {
  isRequired: ReactPropsCheckType;
  (props: any, propName: string, componentName: string, href?: string): ?Error;
};

type React$PropTypes$arrayOf = (typeChecker: ReactPropsCheckType) => ReactPropsChainableTypeChecker;
type React$PropTypes$instanceOf = (expectedClass: any) => ReactPropsChainableTypeChecker;
type React$PropTypes$objectOf = (typeChecker: ReactPropsCheckType) => ReactPropsChainableTypeChecker;
type React$PropTypes$oneOf = (expectedValues: Array<any>) => ReactPropsChainableTypeChecker;
type React$PropTypes$oneOfType = (arrayOfTypeCheckers: Array<ReactPropsCheckType>) => ReactPropsChainableTypeChecker;
type React$PropTypes$shape = (shapeTypes: { [key: string]: ReactPropsCheckType }) => ReactPropsChainableTypeChecker;

type ReactPropTypes = {
  array: React$PropType$Primitive<Array<any>>;
  bool: React$PropType$Primitive<boolean>;
  func: React$PropType$Primitive<Function>;
  number: React$PropType$Primitive<number>;
  object: React$PropType$Primitive<Object>;
  string: React$PropType$Primitive<string>;
  any: React$PropType$Primitive<any>;
  arrayOf: React$PropType$ArrayOf;
  element: React$PropType$Primitive<any>; /* TODO */
  instanceOf: React$PropType$InstanceOf;
  node: React$PropType$Primitive<any>; /* TODO */
  objectOf: React$PropType$ObjectOf;
  oneOf: React$PropType$OneOf;
  oneOfType: React$PropType$OneOfType;
  shape: React$PropType$Shape;
}

declare module react {
  declare var Children: any;
  declare var DOM: any;
  declare var PropTypes: ReactPropTypes;
  declare var version: string;

  declare function initializeTouchEvents(shouldUseTouch: boolean): void;

  declare function checkPropTypes<V>(
    propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>,
    values: V,
    location: string,
    componentName: string,
    getStack: ?(() => ?string)
  ) : void;

  declare var createClass: React$CreateClass;

  declare function cloneElement<Config> (
    element: React$Element<Config>,
    attributes: $Shape<Config>,
    children?: any
  ): React$Element<Config>;

  /**
   * Methods that take an `config` argument of type Config, describing objects
   * whose properties must cover (at least) the difference between the
   * properties in Props and the properties in DefaultProps.  This is intended
   * to model what happens at run time: the config are merged with the default
   * props to obtain the props of a React$Element / React$Component instance.
   */
  declare var createElement: React$CreateElement;

  // TODO: React DOM elements
  declare function createFactory<Config>(
    name: ReactClass<Config>
  ): (config: Config, children?: any) => React$Element<Config>;

  // TODO: React DOM elements
  declare function constructAndRenderComponent<Config>(
    name: ReactClass<Config>,
    config: Config,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  // TODO: React DOM elements
  declare function constructAndRenderComponentByID<Config>(
    name: ReactClass<Config>,
    config: Config,
    id: string
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function findDOMNode(
    componentOrElement : Element | ?React$Component<any, any, any>,
  ): null | Element | Text;

  declare function render<Config>(
    element: React$Element<Config>,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function renderToString(
    element: React$Element<any>
  ): string;
  declare function renderToStaticMarkup(
    element: React$Element<any>
  ): string;

  declare function unmountComponentAtNode(container: any): boolean;

  declare function isValidElement(element: any): boolean;
  declare function withContext(context: any, callback: () => void): any;

  declare var Component: typeof React$Component;
  declare var PureComponent: typeof React$PureComponent;
  declare var Element: typeof React$Element;
}

// TODO Delete this once https://github.com/facebook/react/pull/3031 lands
// and "react" becomes the standard name for this module
declare module React {
  declare var exports: $Exports<'react'>;
}

// TODO: Delete the corresponding method defs from the 'react' module once React
// 0.15 comes out and removes them.
declare module 'react-dom' {
  declare function findDOMNode(
    componentOrElement : Element | ?React$Component<any, any, any>,
  ): null | Element | Text;

  declare function render<Config>(
    element: React$Element<Config>,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function unmountComponentAtNode(container: any): boolean;
  declare var version: string;

  declare function unstable_batchedUpdates<A, B, C, D, E>(
    callback: (a: A, b: B, c: C, d: D, e: E) => mixed,
    a: A,
    b: B,
    c: C,
    d: D,
    e: E
  ): void;
  declare function unstable_renderSubtreeIntoContainer<Config>(
    parentComponent: React$Component<any, any, any>,
    nextElement: React$Element<Config>,
    container: any,
    callback?: () => void
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;
}

// TODO: Delete the corresponding method defs from the 'react' module once React
// 0.15 comes out and removes them.
declare module 'react-dom/server' {
  declare function renderToString(
    element: React$Element<any>
  ): string;
  declare function renderToStaticMarkup(
    element: React$Element<any>
  ): string;
}

declare class SyntheticEvent {
    bubbles: boolean;
    cancelable: boolean;
    currentTarget: EventTarget;
    defaultPrevented: boolean;
    eventPhase: number;
    isDefaultPrevented(): boolean;
    isPropagationStopped(): boolean;
    isTrusted: boolean;
    nativeEvent: Event;
    preventDefault(): void;
    stopPropagation(): void;
    +target: EventTarget;
    timeStamp: number;
    type: string;
    persist(): void;
}

declare class SyntheticClipboardEvent extends SyntheticEvent {
    clipboardData: any;
}

declare class SyntheticCompositionEvent extends SyntheticEvent {
    data: any;
}

declare class SyntheticInputEvent extends SyntheticEvent {
    +target: HTMLInputElement;
    data: any;
}

declare class SyntheticUIEvent extends SyntheticEvent {
    detail: number;
    view: any;
}

declare class SyntheticFocusEvent extends SyntheticUIEvent {
    relatedTarget: EventTarget;
}

declare class SyntheticKeyboardEvent extends SyntheticUIEvent {
    altKey: boolean;
    charCode: number;
    ctrlKey: boolean;
    getModifierState: any;
    key: string;
    keyCode: number;
    locale: string;
    location: number;
    metaKey: boolean;
    repeat: boolean;
    shiftKey: boolean;
    which: number;
}

declare class SyntheticMouseEvent extends SyntheticUIEvent {
    altKey: boolean;
    button: number;
    buttons: number;
    clientX: number;
    clientY: number;
    ctrlKey: boolean;
    getModifierState: any;
    metaKey: boolean;
    pageX: number;
    pageY: number;
    relatedTarget: EventTarget;
    screenX: number;
    screenY: number;
    shiftKey: boolean;
}

declare class SyntheticDragEvent extends SyntheticMouseEvent {
    dataTransfer: any;
}

declare class SyntheticWheelEvent extends SyntheticMouseEvent {
    deltaMode: number;
    deltaX: number;
    deltaY: number;
    deltaZ: number;
}

declare class SyntheticTouchEvent extends SyntheticUIEvent {
    altKey: boolean;
    changedTouches: any;
    ctrlKey: boolean;
    getModifierState: any;
    metaKey: boolean;
    shiftKey: boolean;
    targetTouches: any;
    touches: any;
}

type $JSXIntrinsics = {[k:string]: ReactClass<any>}
<commit_msg>[PR] Grammar fix.<commit_after>/**
 * Copyright (c) 2013-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the "flow" directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 */
/* React */

/**
 * Base class of ES6 React classes, modeled as a polymorphic class whose type
 * parameters are DefaultProps, Props, State.
 */
declare class React$Component<DefaultProps, Props, State> {
  // fields

  static defaultProps: $Abstract<DefaultProps>;
  props: Props;
  state: $Abstract<State>;

  // action methods

  // TODO: partialState could be a function as well
  setState(partialState: $Shape<State>, callback?: () => void): void;

  forceUpdate(callback?: () => void): void;

  // lifecycle methods

  render(): ?React$Element<any>;
  componentWillMount(): void;
  componentDidMount(component?: any): void;
  componentWillReceiveProps(nextProps: Props, nextContext?: any): void;
  shouldComponentUpdate(nextProps: Props, nextState: State, nextContext: any): boolean;
  componentWillUpdate(nextProps: Props, nextState: State, nextContext: any): void;
  componentDidUpdate(nextProps: Props, nextState: State, nextContext: any, component: any): void;
  componentWillUnmount(): void;

  // long tail of other stuff not modeled very well

  refs: any;
  context: any;
  getChildContext(): any;
  static displayName: string;
  static childContextTypes: any;
  static contextTypes: any;
  static propTypes: $Subtype<{[_: $Keys<Props>]: any}>; //object whose keys are in PropTypes
}

declare class React$PureComponent<DefaultProps, Props, State> extends React$Component<DefaultProps, Props, State> {
  // TODO: Due to bugs in Flow's handling of React.createClass, some fields
  // already declared in the base class need to be redeclared below. Ideally
  // they should simply be inherited.

  static defaultProps: $Abstract<DefaultProps>;
  props: Props;
  state: $Abstract<State>;
}

/**
 * Base class of legacy React classes, which extends the base class of ES6 React
 * classes and supports additional methods.
 */
declare class LegacyReactComponent<DefaultProps, Props, State> extends React$Component<DefaultProps, Props, State> {
  // additional methods

  replaceState(state: State, callback?: () => void): void;

  isMounted(): bool;

  // TODO: Due to bugs in Flow's handling of React.createClass, some fields
  // already declared in the base class need to be redeclared below. Ideally
  // they should simply be inherited.

  static defaultProps: DefaultProps;
  props: Props;
  state: State;
}

/**
 * Type of a React class (not to be confused with the type of instances of a
 * React class, which is the React class itself). A React class is any subclass
 * of React$Component. We make the type of a React class parametric over Config,
 * which is derived from some of the type parameters (DefaultProps, Props) of
 * React$Component, abstracting away others (State); whereas a React$Component
 * type is useful for checking the definition of a React class, a ReactClass
 * type (and the corresponding React$Element type, see below) is useful for
 * checking the uses of a React class. The required constraints are set up using
 * a "helper" type alias, that takes an additional type parameter C representing
 * the React class, which is then abstracted with an existential type (*). The *
 * can be thought of as an "auto" instruction to the typechecker, telling it to
 * fill in the type from context.
 */
type ReactClass<Config> = _ReactClass<*, *, Config, *>;
type _ReactClass<DefaultProps, Props, Config: $Diff<Props, DefaultProps>, C: React$Component<DefaultProps, Props, any>> = Class<C>;

// TODO: DefaultProps and Props are needed to type some introspection APIs
// below, but in general, Config does not carry enough information to recover
// them faithfully. For now, we trade off that additional precision for overall
// simplicity of the model. In the future, we may provide more powerful
// introspection features in types, at which point Config would carry enough
// information to faithfully recover DefaultProps and Props.
type $PropsOf<Config> = any
type $DefaultPropsOf<Config> = any

/**
 * Type of a React element. React elements are commonly created using JSX
 * literals, which desugar to React.createElement calls (see below). The type
 * parameterization of React$Element mimics that of ReactClass (see above).
 */
declare class React$Element<Config> {
  type: ReactClass<Config>;
  props: $PropsOf<Config>;
  key: ?string;
  ref: any;
}

type ReactPropsCheckType = (
  props: any,
  propName: string,
  componentName: string,
  href?: string) => ?Error;

type ReactPropsChainableTypeChecker = {
  isRequired: ReactPropsCheckType;
  (props: any, propName: string, componentName: string, href?: string): ?Error;
};

type React$PropTypes$arrayOf = (typeChecker: ReactPropsCheckType) => ReactPropsChainableTypeChecker;
type React$PropTypes$instanceOf = (expectedClass: any) => ReactPropsChainableTypeChecker;
type React$PropTypes$objectOf = (typeChecker: ReactPropsCheckType) => ReactPropsChainableTypeChecker;
type React$PropTypes$oneOf = (expectedValues: Array<any>) => ReactPropsChainableTypeChecker;
type React$PropTypes$oneOfType = (arrayOfTypeCheckers: Array<ReactPropsCheckType>) => ReactPropsChainableTypeChecker;
type React$PropTypes$shape = (shapeTypes: { [key: string]: ReactPropsCheckType }) => ReactPropsChainableTypeChecker;

type ReactPropTypes = {
  array: React$PropType$Primitive<Array<any>>;
  bool: React$PropType$Primitive<boolean>;
  func: React$PropType$Primitive<Function>;
  number: React$PropType$Primitive<number>;
  object: React$PropType$Primitive<Object>;
  string: React$PropType$Primitive<string>;
  any: React$PropType$Primitive<any>;
  arrayOf: React$PropType$ArrayOf;
  element: React$PropType$Primitive<any>; /* TODO */
  instanceOf: React$PropType$InstanceOf;
  node: React$PropType$Primitive<any>; /* TODO */
  objectOf: React$PropType$ObjectOf;
  oneOf: React$PropType$OneOf;
  oneOfType: React$PropType$OneOfType;
  shape: React$PropType$Shape;
}

declare module react {
  declare var Children: any;
  declare var DOM: any;
  declare var PropTypes: ReactPropTypes;
  declare var version: string;

  declare function initializeTouchEvents(shouldUseTouch: boolean): void;

  declare function checkPropTypes<V>(
    propTypes: $Subtype<{[_: $Keys<V>]: ReactPropsCheckType}>,
    values: V,
    location: string,
    componentName: string,
    getStack: ?(() => ?string)
  ) : void;

  declare var createClass: React$CreateClass;

  declare function cloneElement<Config> (
    element: React$Element<Config>,
    attributes: $Shape<Config>,
    children?: any
  ): React$Element<Config>;

  /**
   * Methods that take a `config` argument of type Config, describing objects
   * whose properties must cover (at least) the difference between the
   * properties in Props and the properties in DefaultProps.  This is intended
   * to model what happens at run time: the config are merged with the default
   * props to obtain the props of a React$Element / React$Component instance.
   */
  declare var createElement: React$CreateElement;

  // TODO: React DOM elements
  declare function createFactory<Config>(
    name: ReactClass<Config>
  ): (config: Config, children?: any) => React$Element<Config>;

  // TODO: React DOM elements
  declare function constructAndRenderComponent<Config>(
    name: ReactClass<Config>,
    config: Config,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  // TODO: React DOM elements
  declare function constructAndRenderComponentByID<Config>(
    name: ReactClass<Config>,
    config: Config,
    id: string
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function findDOMNode(
    componentOrElement : Element | ?React$Component<any, any, any>,
  ): null | Element | Text;

  declare function render<Config>(
    element: React$Element<Config>,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function renderToString(
    element: React$Element<any>
  ): string;
  declare function renderToStaticMarkup(
    element: React$Element<any>
  ): string;

  declare function unmountComponentAtNode(container: any): boolean;

  declare function isValidElement(element: any): boolean;
  declare function withContext(context: any, callback: () => void): any;

  declare var Component: typeof React$Component;
  declare var PureComponent: typeof React$PureComponent;
  declare var Element: typeof React$Element;
}

// TODO Delete this once https://github.com/facebook/react/pull/3031 lands
// and "react" becomes the standard name for this module
declare module React {
  declare var exports: $Exports<'react'>;
}

// TODO: Delete the corresponding method defs from the 'react' module once React
// 0.15 comes out and removes them.
declare module 'react-dom' {
  declare function findDOMNode(
    componentOrElement : Element | ?React$Component<any, any, any>,
  ): null | Element | Text;

  declare function render<Config>(
    element: React$Element<Config>,
    container: any
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;

  declare function unmountComponentAtNode(container: any): boolean;
  declare var version: string;

  declare function unstable_batchedUpdates<A, B, C, D, E>(
    callback: (a: A, b: B, c: C, d: D, e: E) => mixed,
    a: A,
    b: B,
    c: C,
    d: D,
    e: E
  ): void;
  declare function unstable_renderSubtreeIntoContainer<Config>(
    parentComponent: React$Component<any, any, any>,
    nextElement: React$Element<Config>,
    container: any,
    callback?: () => void
  ): React$Component<$DefaultPropsOf<Config>, $PropsOf<Config>, any>;
}

// TODO: Delete the corresponding method defs from the 'react' module once React
// 0.15 comes out and removes them.
declare module 'react-dom/server' {
  declare function renderToString(
    element: React$Element<any>
  ): string;
  declare function renderToStaticMarkup(
    element: React$Element<any>
  ): string;
}

declare class SyntheticEvent {
    bubbles: boolean;
    cancelable: boolean;
    currentTarget: EventTarget;
    defaultPrevented: boolean;
    eventPhase: number;
    isDefaultPrevented(): boolean;
    isPropagationStopped(): boolean;
    isTrusted: boolean;
    nativeEvent: Event;
    preventDefault(): void;
    stopPropagation(): void;
    +target: EventTarget;
    timeStamp: number;
    type: string;
    persist(): void;
}

declare class SyntheticClipboardEvent extends SyntheticEvent {
    clipboardData: any;
}

declare class SyntheticCompositionEvent extends SyntheticEvent {
    data: any;
}

declare class SyntheticInputEvent extends SyntheticEvent {
    +target: HTMLInputElement;
    data: any;
}

declare class SyntheticUIEvent extends SyntheticEvent {
    detail: number;
    view: any;
}

declare class SyntheticFocusEvent extends SyntheticUIEvent {
    relatedTarget: EventTarget;
}

declare class SyntheticKeyboardEvent extends SyntheticUIEvent {
    altKey: boolean;
    charCode: number;
    ctrlKey: boolean;
    getModifierState: any;
    key: string;
    keyCode: number;
    locale: string;
    location: number;
    metaKey: boolean;
    repeat: boolean;
    shiftKey: boolean;
    which: number;
}

declare class SyntheticMouseEvent extends SyntheticUIEvent {
    altKey: boolean;
    button: number;
    buttons: number;
    clientX: number;
    clientY: number;
    ctrlKey: boolean;
    getModifierState: any;
    metaKey: boolean;
    pageX: number;
    pageY: number;
    relatedTarget: EventTarget;
    screenX: number;
    screenY: number;
    shiftKey: boolean;
}

declare class SyntheticDragEvent extends SyntheticMouseEvent {
    dataTransfer: any;
}

declare class SyntheticWheelEvent extends SyntheticMouseEvent {
    deltaMode: number;
    deltaX: number;
    deltaY: number;
    deltaZ: number;
}

declare class SyntheticTouchEvent extends SyntheticUIEvent {
    altKey: boolean;
    changedTouches: any;
    ctrlKey: boolean;
    getModifierState: any;
    metaKey: boolean;
    shiftKey: boolean;
    targetTouches: any;
    touches: any;
}

type $JSXIntrinsics = {[k:string]: ReactClass<any>}
<|endoftext|>


<commit_before>const bunyan = require('bunyan');
const Context = require('./context');

class Robot {
  constructor(integration, webhook) {
    this.integration = integration;
    this.webhook = webhook;

    this.log = bunyan.createLogger({
      name: 'PRobot',
      level: process.env.LOG_LEVEL || 'info'
    });
  }

  on(event, callback) {
    const [name, action] = event.split('.');

    return this.webhook.on(name, event => {
      if (!action || action === event.payload.action) {
        callback(event, new Context(event));
      }
    });
  }

  auth(id) {
    return this.integration.asInstallation(id);
  }
}

module.exports = (...args) => new Robot(...args);
<commit_msg>Add shorthand for robot.log<commit_after>const bunyan = require('bunyan');
const Context = require('./context');

const logger = bunyan.createLogger({
  name: 'PRobot',
  level: process.env.LOG_LEVEL || 'debug'
});

class Robot {
  constructor(integration, webhook) {
    this.integration = integration;
    this.webhook = webhook;
  }

  on(event, callback) {
    const [name, action] = event.split('.');

    return this.webhook.on(name, event => {
      if (!action || action === event.payload.action) {
        callback(event, new Context(event));
      }
    });
  }

  auth(id) {
    return this.integration.asInstallation(id);
  }

  log(...args) {
    return logger.debug(...args);
  }
}

// Add level methods on the logger
['trace', 'debug', 'info', 'warn', 'error', 'fatal'].forEach(level => {
  Robot.prototype.log[level] = logger[level].bind(logger);
});

module.exports = (...args) => new Robot(...args);
<|endoftext|>


<commit_before>var http        = require('http')
var https       = require('https')
var HttpProxy   = require('http-proxy')
var midware     = require('midware')
var parseUrl    = require('url').parse
var replay      = require('./replay')
var middleware = require('./middleware')
var assign      = require('lodash').assign

module.exports = Route

function Route(path) {
  this.opts    = {}
  this.replays = []
  this.path    = path
  this.mw      = midware()
  this.proxy   = new HttpProxy()
}

Route.prototype.target  =
Route.prototype.forward = function (url) {
  this.opts.target = url
  return this
}

Route.prototype.balance = function (urls) {
  if (Array.isArray(urls)) {
    this.opts.balance = urls
  }
  return this
}

Route.prototype.options = function (opts) {
  assign(this.opts, opts)
  return this
}

Route.prototype.replay = function (url, opts) {
  if (typeof url === 'string') {
    url = { target: url }
  }
  this.replays.push(assign({}, url, opts))
  return this
}

Route.prototype.use = function () {
  this.mw.apply(null, arguments)
  return this
}

Route.prototype.on = function () {
  this.proxy.on.apply(this.proxy, arguments)
  return this
}

Route.prototype.once = function () {
  this.proxy.once.apply(this.proxy, arguments)
  return this
}

Route.prototype.off = function () {
  this.proxy.off.apply(this.proxy, arguments)
  return this
}

Route.prototype.host = function (host) {
  this.mw(middleware.host(host))
  return this
}

Route.prototype.transformResponseBody = function (transformer) {
  this.mw(middleware.responseBody(transformer))
  return this
}

Route.prototype.transformRequestBody = function (transformer) {
  this.mw(middleware.requestBody(transformer))
  return this
}

Route.prototype.toPath = function (path, params) {
  this.mw(middleware.toPath(path, params))
  return this
}

Route.prototype.headers = function (headers) {
  this.mw(middleware.headers(headers))
  return this
}

Route.prototype.handle = function (options, req, res) {
  var route = this
  var opts = assign({}, options, this.opts)

  // Dispatch the route middleware
  this.mw.run(req, res, forwarder)

  function forwarder(err) {
    if (err) {
      return route.proxy.emit('route:error', err, req, res)
    }

    // Forward the request
    if (opts.target || opts.balance) {
      forwardRequest(req, res, route, opts)
    } else {
      // Reply with an error if target server was not defined
      missingTargetError(route, req, res)
    }

    // Then replay it, if necessary
    replayRequest(req, route, opts)
  }
}

function forwardRequest(req, res, route, opts) {
  // Balance the request, if required
  var balance = opts.balance
  if (balance) {
    opts.target = balance.shift()
    balance.push(opts.target)
  }

  if (!opts.target) { return }

  if (opts.forwardHost) {
    req.headers.host = parseUrl(opts.target).host
  }

  // Forward the request to the main target
  route.proxy.web(req, res, opts, handler)

  function handler(err) {
    route.proxy.emit('proxy:error', err, req, res)
    if (!res.headersSent) {
      res.writeHead(502, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({ message: err.message || err }))
    }
  }
}

function replayRequest(req, route, opts) {
  var replays = route.replays.length
    ? route.replays
    : opts.replays

  replays.map(function (replay) {
    return assign({}, opts, replay)
  })
  .forEach(replay(req, route))
}

function missingTargetError(route, req, res) {
  var error = new Error('Target URL was not defined for this route')
  route.proxy.emit('route:error', error, req, res)

  if (!res.headersSent) {
    res.writeHead(404, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ message: error.message }))
  }
}
<commit_msg>refactor(route)<commit_after>var http        = require('http')
var https       = require('https')
var HttpProxy   = require('http-proxy')
var midware     = require('midware')
var parseUrl    = require('url').parse
var replay      = require('./replay')
var middleware = require('./middleware')
var assign      = require('lodash').assign

module.exports = Route

function Route(path) {
  this.opts    = {}
  this.replays = []
  this.path    = path
  this.mw      = midware()
  this.proxy   = new HttpProxy()
}

Route.prototype.target  =
Route.prototype.forward = function (url) {
  this.opts.target = url
  return this
}

Route.prototype.balance = function (urls) {
  if (Array.isArray(urls)) {
    this.opts.balance = urls
  }
  return this
}

Route.prototype.options = function (opts) {
  assign(this.opts, opts)
  return this
}

Route.prototype.replay = function (url, opts) {
  if (typeof url === 'string') {
    url = { target: url }
  }
  this.replays.push(assign({}, url, opts))
  return this
}

Route.prototype.use = function () {
  this.mw.apply(null, arguments)
  return this
}

Route.prototype.on = function () {
  this.proxy.on.apply(this.proxy, arguments)
  return this
}

Route.prototype.once = function () {
  this.proxy.once.apply(this.proxy, arguments)
  return this
}

Route.prototype.off = function () {
  this.proxy.off.apply(this.proxy, arguments)
  return this
}

Route.prototype.host = function (host) {
  this.mw(middleware.host(host))
  return this
}

Route.prototype.transformResponseBody = function (transformer) {
  this.mw(middleware.responseBody(transformer))
  return this
}

Route.prototype.transformRequestBody = function (transformer) {
  this.mw(middleware.requestBody(transformer))
  return this
}

Route.prototype.toPath = function (path, params) {
  this.mw(middleware.toPath(path, params))
  return this
}

Route.prototype.headers = function (headers) {
  this.mw(middleware.headers(headers))
  return this
}

Route.prototype.handle = function (options, req, res) {
  var route = this
  var opts = assign({}, options, this.opts)

  // Dispatch the route middleware
  this.mw.run(req, res, forwarder)

  function forwarder(err) {
    if (err) {
      return route.proxy.emit('route:error', err, req, res)
    }

    // Forward the request
    if (opts.target || opts.balance) {
      forwardRequest(req, res, route, opts)
    } else {
      // Reply with an error if target server was not defined
      missingTargetError(route, req, res)
    }

    // Then replay it, if necessary
    replayRequest(req, route, opts)
  }
}

function forwardRequest(req, res, route, opts) {
  // Balance the request, if required
  var balance = opts.balance
  if (balance && balance.length) {
    opts.target = permute(opts.balance)
  }

  if (!opts.target) { return }

  if (opts.forwardHost) {
    req.headers.host = parseUrl(opts.target).host
  }

  // Forward the request to the main target
  route.proxy.web(req, res, opts, handler)

  function handler(err) {
    route.proxy.emit('proxy:error', err, req, res)
    if (!res.headersSent) {
      res.writeHead(502, { 'Content-Type': 'application/json' })
      res.end(JSON.stringify({ message: err.message || err }))
    }
  }
}

function replayRequest(req, route, opts) {
  var replays = route.replays.length
    ? route.replays
    : opts.replays

  replays.map(function (replay) {
    return assign({}, opts, replay)
  })
  .forEach(replay(req, route))
}

function missingTargetError(route, req, res) {
  var error = new Error('Target URL was not defined for this route')
  route.proxy.emit('route:error', error, req, res)

  if (!res.headersSent) {
    res.writeHead(404, { 'Content-Type': 'application/json' })
    res.end(JSON.stringify({ message: error.message }))
  }
}

function permute(arr) {
  var item = arr.shift()
  arr.push(item)
  return item
}
<|endoftext|>


<commit_before>var _ = require('underscore');

var Rules = function(param, rules)
{
	this.param = param;
	this.rules = rules;
};

Rules.prototype.Error = function(message, rule, value)
{
	switch(typeof(this.rules.error))
	{
		case 'string':
			message = this.rules.error;
			break;

		case 'object':

			if(this.rules.error[rule])
			{
				message = this.rules.error[rule];
			}
			else if(this.rules.error['default'])
			{
				message = this.rules.error['default'];
			}

			break;
	}

   if(_.isString(value))
      message = message.replace(/%v/, value.toString());

   if(_.isString(rule))
      message = message.replace(/%r/, rule);

	return message.replace(/%p/, this.param).replace(/%v/, "value").replace(/%r/, "rule");
};

Rules.prototype.apply = function(value)
{
	if(_.isUndefined(value) && !_.isUndefined(this.rules['default']))
	{
		value = this.rules['default'];
	}

	if(this.rules.required)
	{
		if(this.rules.required && _.isUndefined(value))
		{
			throw this.Error("%p is a required parameter", "required", value);
		}
	}
   // if value is nore required and is undefined, no more rules need to be run
   else if(_.isUndefined(value))
      return value;

	if(this.rules.filters)
	{
		value = this.filter(value);
	}

	if(this.rules.type)
	{
      if(typeof(this.rules.type) == "string" && typeof(is[this.rules.type]) == "function")
      {
         if(!is[this.rules.type](value))
            throw this.Error("%s is not a " + this.rules.type, "type", value);
      }
      else if(typeof(this.rules.type == "function"))
      {
         if(!this.rules.type(value))
            throw this.Error("%s is not a valid type", "type", value);
      }
      else
      {
         throw this.Error("%s is not a valid type", "type", value);
      }
	}

	if(this.rules.properties)
	{
		this.check(value);
	}

	return value;
};

Rules.prototype.filter = function(value)
{
	switch(typeof(this.rules.filters))
	{
		case 'function':
			value = this.rules.filters(value);
			break;

		case 'string':

			if(typeof(filters[this.rules.filters]) === 'function')
			{
				value = filters[this.rules.filters](value);
			}

			break;

		case 'object':

			if(Array.isArray(this.rules.filters))
			{
				this.rules.filters.forEach(function(filter) { value = filters[filter](value); });
			}

			break;
	}

	return value;
};

Rules.prototype.check = function(value)
{
	switch(typeof(this.rules.properties))
	{
		case 'function':

			if(!this.rules.properties(value))
				throw this.Error("%s is not valid");

			break;

		case 'object':

			var properties = Object.keys(this.rules.properties);

			for(var i = 0; i < properties.length; i++)
			{
				var property = properties[i];

				if(typeof(checks[property]) === "function")
				{
					var args = this.rules.properties[property];

					if(!checks[property].apply(null, [value, args]))
						throw this.Error("%p failed %r with %v", property);
				}
				else if(typeof(this.rules.properties[property]) === "function")
				{
					if(!this.rules.properties[property].apply(null, [value]))
						throw this.Error("%p failed on %r with %v", property);
				}
			}

			break;
	}
};

var checks =
{
	'max': function(value, length)
	{
      if(Array.isArray(value) || typeof(value) == "string")
      {
         return value.length <= length;
      }
      else if(typeof(value) == "number")
      {
         return value <= length;
      }
      else
      {
         return false;
      }
	},

	'min': function(value, length)
	{
      if(Array.isArray(value) || typeof(value) == "string")
      {
         return value.length >= length;
      }
      else if(typeof(value) == "number")
      {
         return value >= length;
      }
      else
      {
         return false;
      }
	},

	'regex': function(value, regex)
	{
		return regex.test(value);
	},

	'in': function(value, list)
	{
		return list.indexOf(value) != -1;
	}
};

var is =
{
	'string': function(value)
	{
		return typeof(value) == 'string';
	},

   'alphanum': function(value)
   {
      return (/^[a-z0-9]+$/i).test(value);
   },

   'alpha': function(value)
   {
      return (/^[a-z]+$/i).test(value);
   },

	'object': function(value)
	{
		return typeof(value) == 'object';
	},

	'array': function(value)
	{
		 return Array.isArray(value);
	},

	'date': function(value)
	{
		return _.isDate(value);
	},

	'number': function(value)
	{
		return _.isNumber(value);
	},

	'int': function(value)
	{
		return typeof(value) == 'number' && value % 1 === 0;
	},

	'boolean': function(value)
	{
		return _.isBoolean(value);
	},

	'float': function(value)
	{
		return typeof(value) == 'number';
	},

	'email': function(value)
	{
		return (/[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?/).test(value);
	},

	'url': function(value)
	{
		return (/^(http(s)?:\/\/)?([\w\-]+\.{1})*(([\w\-]*){1}(\.{1}[A-Za-z]{2,4}){1}){1}(\:{1}\d*)?([\?\/|\#]+[\@\~\;\+\'\#\,\.\%\-\/\&\?\=\w\$\s]*)*$/i).test(value);
	},

	'zipcode': function(value)
	{
		return (/d+\{5\}/).test(value);
	}
};

var filters =
{
	'toInt': function(value)
	{
		return parseInt(value, 10);
	},

	'toFloat': function(value)
	{
		return parseFloat(value, 10);
	},

	'toString': function(value)
	{
		return value.toString();
	},

	'toDate': function(value)
	{
		return new Date(value);
	},

	'toBoolean': function(value)
	{
		if(value === 1 || value === true || /true|on|yes|1/.test(value))
			return true;
		else if(value === 0 || value === false || /false|off|no|0/.test(value))
			return false;
		else
			return value;
	},

	'trim': function(value)
	{
		return _.isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
	}
};

exports.create = function(param, rules) { return new Rules(param, rules); };
exports.types = is;
exports.filters = filters;
exports.properties = checks;
<commit_msg>don't allow empty strings, replace with default if empty valued<commit_after>var _ = require('underscore');

var Rules = function(param, rules)
{
	this.param = param;
	this.rules = rules;
};

Rules.prototype.Error = function(message, rule, value)
{
	switch(typeof(this.rules.error))
	{
		case 'string':
			message = this.rules.error;
			break;

		case 'object':

			if(this.rules.error[rule])
			{
				message = this.rules.error[rule];
			}
			else if(this.rules.error['default'])
			{
				message = this.rules.error['default'];
			}

			break;
	}

   if(_.isString(value))
      message = message.replace(/%v/, value.toString());

   if(_.isString(rule))
      message = message.replace(/%r/, rule);

	return message.replace(/%p/, this.param).replace(/%v/, "value").replace(/%r/, "rule");
};

Rules.prototype.apply = function(value)
{
	if(_.isEmpty(value) && !_.isUndefined(this.rules['default']))
	{
		value = this.rules['default'];
	}

	if(this.rules.required)
	{
		if(this.rules.required && _.isUndefined(value))
		{
			throw this.Error("%p is a required parameter", "required", value);
		}
	}
   // if value is nore required and is undefined, no more rules need to be run
   else if(_.isUndefined(value))
      return value;

	if(this.rules.filters)
	{
		value = this.filter(value);
	}

	if(this.rules.type)
	{
      if(typeof(this.rules.type) == "string" && typeof(is[this.rules.type]) == "function")
      {
         if(!is[this.rules.type](value))
            throw this.Error("%p is not a " + this.rules.type, "type", value);
      }
      else if(typeof(this.rules.type == "function"))
      {
         if(!this.rules.type(value))
            throw this.Error("%p is not a valid type", "type", value);
      }
      else
      {
         throw this.Error("%p is not a valid type", "type", value);
      }
	}

	if(this.rules.properties)
	{
		this.check(value);
	}

	return value;
};

Rules.prototype.filter = function(value)
{
	switch(typeof(this.rules.filters))
	{
		case 'function':
			value = this.rules.filters(value);
			break;

		case 'string':

			if(typeof(filters[this.rules.filters]) === 'function')
			{
				value = filters[this.rules.filters](value);
			}

			break;

		case 'object':

			if(Array.isArray(this.rules.filters))
			{
				this.rules.filters.forEach(function(filter) { value = filters[filter](value); });
			}

			break;
	}

	return value;
};

Rules.prototype.check = function(value)
{
	switch(typeof(this.rules.properties))
	{
		case 'function':

			if(!this.rules.properties(value))
				throw this.Error("%p is not valid");

			break;

		case 'object':

			var properties = Object.keys(this.rules.properties);

			for(var i = 0; i < properties.length; i++)
			{
				var property = properties[i];

				if(typeof(checks[property]) === "function")
				{
					var args = this.rules.properties[property];

					if(!checks[property].apply(null, [value, args]))
						throw this.Error("%p failed %r with %v", property);
				}
				else if(typeof(this.rules.properties[property]) === "function")
				{
					if(!this.rules.properties[property].apply(null, [value]))
						throw this.Error("%p failed on %r with %v", property);
				}
			}

			break;
	}
};

var checks =
{
	'max': function(value, length)
	{
      if(Array.isArray(value) || typeof(value) == "string")
      {
         return value.length <= length;
      }
      else if(typeof(value) == "number")
      {
         return value <= length;
      }
      else
      {
         return false;
      }
	},

	'min': function(value, length)
	{
      if(Array.isArray(value) || typeof(value) == "string")
      {
         return value.length >= length;
      }
      else if(typeof(value) == "number")
      {
         return value >= length;
      }
      else
      {
         return false;
      }
	},

	'regex': function(value, regex)
	{
		return regex.test(value);
	},

	'in': function(value, list)
	{
		return list.indexOf(value) != -1;
	}
};

var is =
{
	'string': function(value)
	{
		return typeof(value) == 'string' && value !== "";
	},

   'alphanum': function(value)
   {
      return (/^[a-z0-9]+$/i).test(value);
   },

   'alpha': function(value)
   {
      return (/^[a-z]+$/i).test(value);
   },

	'object': function(value)
	{
		return typeof(value) == 'object';
	},

	'array': function(value)
	{
		 return Array.isArray(value);
	},

	'date': function(value)
	{
		return _.isDate(value);
	},

	'number': function(value)
	{
		return _.isNumber(value);
	},

	'int': function(value)
	{
		return typeof(value) == 'number' && value % 1 === 0;
	},

	'boolean': function(value)
	{
		return _.isBoolean(value);
	},

	'float': function(value)
	{
		return typeof(value) == 'number';
	},

	'email': function(value)
	{
		return (/[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+(?:\.[a-z0-9!#$%&'*+\/=?\^_`{|}~\-]+)*@(?:[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9\-]*[a-z0-9])?/).test(value);
	},

	'url': function(value)
	{
		return (/^(http(s)?:\/\/)?([\w\-]+\.{1})*(([\w\-]*){1}(\.{1}[A-Za-z]{2,4}){1}){1}(\:{1}\d*)?([\?\/|\#]+[\@\~\;\+\'\#\,\.\%\-\/\&\?\=\w\$\s]*)*$/i).test(value);
	},

	'zipcode': function(value)
	{
		return (/d+\{5\}/).test(value);
	}
};

var filters =
{
	'toInt': function(value)
	{
		return parseInt(value, 10);
	},

	'toFloat': function(value)
	{
		return parseFloat(value, 10);
	},

	'toString': function(value)
	{
		return value.toString();
	},

	'toDate': function(value)
	{
		return new Date(value);
	},

	'toBoolean': function(value)
	{
		if(value === 1 || value === true || /true|on|yes|1/.test(value))
			return true;
		else if(value === 0 || value === false || /false|off|no|0/.test(value))
			return false;
		else
			return value;
	},

	'trim': function(value)
	{
		return _.isString(value) ? value.replace(/^\s\s*/, '').replace(/\s\s*$/, '') : value;
	}
};

exports.create = function(param, rules) { return new Rules(param, rules); };
exports.types = is;
exports.filters = filters;
exports.properties = checks;
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {defer} = require("sdk/core/promise");
const {Cc, Ci} = require("chrome");
const {Request} = require("sdk/request");
const {storage} = require("sdk/simple-storage");
const {clearTimeout, setTimeout} = require("sdk/timers");

const API_ENDPOINT = "https://dothiv-registry.appspot.com/redirects";
const API_ACCEPT = "application/json";

const UPDATE_TIMER_ID = "dothiv-update-rules";
// Fetch new rules from the server at most once a day.
const FETCH_INTERVAL_SECS = 60 * 60 * 24;
// Fetches time out after 30s without a response.
const FETCH_TIMEOUT_SECS = 30;
// Wait 30s before retrying when fetching rules fails with an empty cache.
const FETCH_RETRY_SECS = 30;
// Retry for max. 5 minutes.
const FETCH_MAX_RETRIES = 10;

let active = false;
let cache = new Map();
let retries = 0;

exports.start = function () {
  active = true;
  cache = compile(storage.rules || []);

  // Register an update timer.
  let utm = Cc["@mozilla.org/updates/timer-manager;1"]
              .getService(Ci.nsIUpdateTimerManager);
  utm.registerTimer(UPDATE_TIMER_ID, update, FETCH_INTERVAL_SECS);

  // Fetch rules immediately if the cache is empty.
  if (cache.size == 0) {
    update();
  }
};

exports.stop = function () {
  active = false;
};

exports.has = function (host) {
  return cache.has(host);
};

exports.get = function (host) {
  return cache.get(host);
};

// Update the rules.
function update() {
  // We can't unregister timers so let's ignore updates if disabled.
  if (!active) {
    return;
  }

  fetch().then(data => {
    retries = 0;
    cache = compile(storage.rules = data);
  }, err => {
    // If the cache is empty let's retry real quick.
    if (cache.size == 0) {
      setTimeout(retry, FETCH_RETRY_SECS * 1000);
    }
  });
}

// Fetching failed, retry.
function retry() {
  if (++retries <= FETCH_MAX_RETRIES) {
    update();
  } else {
    retries = 0;
  }
}

// Fetch new rules from the server.
function fetch() {
  let {promise, resolve, reject} = defer();
  let timeout = setTimeout(reject, FETCH_TIMEOUT_SECS * 1000);

  Request({
    url: API_ENDPOINT,
    headers: {"Accept": API_ACCEPT},
    anonymous: true,

    onComplete: function (resp) {
      // The add-on could've been disabled in the meantime.
      if (!active) {
        return;
      }

      clearTimeout(timeout);

      if (resp.json) {
        resolve(resp.json);
      } else {
        reject();
      }
    }
  }).get();

  return promise;
}

// Convert the given rule set into a convenient data structure.
function compile(rulesets) {
  let compiled = new Map();

  for (let ruleset of rulesets) {
    let data = {rules: ruleset.rules};
    for (let rule of data.rules) {
      rule.from = new RegExp(rule.from);
    }

    data.exceptions = ruleset.exceptions || [];
    data.exceptions = data.exceptions.map(ex => new RegExp(ex));

    for (let host of ruleset.hosts) {
      compiled.set(host, data);
    }
  }

  return compiled;
}
<commit_msg>update rules twice a day<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const {defer} = require("sdk/core/promise");
const {Cc, Ci} = require("chrome");
const {Request} = require("sdk/request");
const {storage} = require("sdk/simple-storage");
const {clearTimeout, setTimeout} = require("sdk/timers");

const API_ENDPOINT = "https://dothiv-registry.appspot.com/redirects";
const API_ACCEPT = "application/json";

const UPDATE_TIMER_ID = "dothiv-update-rules";
// Fetch new rules from the server at most twice a day.
const FETCH_INTERVAL_SECS = 60 * 60 * 12;
// Fetches time out after 30s without a response.
const FETCH_TIMEOUT_SECS = 30;
// Wait 30s before retrying when fetching rules fails with an empty cache.
const FETCH_RETRY_SECS = 30;
// Retry for max. 5 minutes.
const FETCH_MAX_RETRIES = 10;

let active = false;
let cache = new Map();
let retries = 0;

exports.start = function () {
  active = true;
  cache = compile(storage.rules || []);

  // Register an update timer.
  let utm = Cc["@mozilla.org/updates/timer-manager;1"]
              .getService(Ci.nsIUpdateTimerManager);
  utm.registerTimer(UPDATE_TIMER_ID, update, FETCH_INTERVAL_SECS);

  // Fetch rules immediately if the cache is empty.
  if (cache.size == 0) {
    update();
  }
};

exports.stop = function () {
  active = false;
};

exports.has = function (host) {
  return cache.has(host);
};

exports.get = function (host) {
  return cache.get(host);
};

// Update the rules.
function update() {
  // We can't unregister timers so let's ignore updates if disabled.
  if (!active) {
    return;
  }

  fetch().then(data => {
    retries = 0;
    cache = compile(storage.rules = data);
  }, err => {
    // If the cache is empty let's retry real quick.
    if (cache.size == 0) {
      setTimeout(retry, FETCH_RETRY_SECS * 1000);
    }
  });
}

// Fetching failed, retry.
function retry() {
  if (++retries <= FETCH_MAX_RETRIES) {
    update();
  } else {
    retries = 0;
  }
}

// Fetch new rules from the server.
function fetch() {
  let {promise, resolve, reject} = defer();
  let timeout = setTimeout(reject, FETCH_TIMEOUT_SECS * 1000);

  Request({
    url: API_ENDPOINT,
    headers: {"Accept": API_ACCEPT},
    anonymous: true,

    onComplete: function (resp) {
      // The add-on could've been disabled in the meantime.
      if (!active) {
        return;
      }

      clearTimeout(timeout);

      if (resp.json) {
        resolve(resp.json);
      } else {
        reject();
      }
    }
  }).get();

  return promise;
}

// Convert the given rule set into a convenient data structure.
function compile(rulesets) {
  let compiled = new Map();

  for (let ruleset of rulesets) {
    let data = {rules: ruleset.rules};
    for (let rule of data.rules) {
      rule.from = new RegExp(rule.from);
    }

    data.exceptions = ruleset.exceptions || [];
    data.exceptions = data.exceptions.map(ex => new RegExp(ex));

    for (let host of ruleset.hosts) {
      compiled.set(host, data);
    }
  }

  return compiled;
}
<|endoftext|>


<commit_before>'use strict'
var estraverse = require('estraverse')

// Node type unknown to estraverse
var keys = {
	ParenthesizedExpression: ['expression'],
}

function blocks(a, isEnd) {
	var bs = []
	for (var i = 0; i < a.length;) {
		for (var j = i + 1; j < a.length; j++)
			if (isEnd(a[j], j))
				break
		bs.push(a.slice(i, j))
		i = j
	}
	return bs
}

function cmp(a, b) {
	if (a < b)
		return -1
	if (a > b)
		return 1
	return 0
}

function cmpCases(a, b) {
	function key(x) {
		x = x.test
		if (!x)
			return '\uffff'
		switch (x.type) {
		case 'Identifier':
			return x.name
		case 'Literal':
			return x.value
		}
	}

	return cmp(key(a), key(b))
}

function hasTerminator(c) {
	var a = c.consequent
	if (!a.length)
		return
	return isTerminator(last(a))
}

function hoistComments(a) {
	var comment
	for (var i = 0; i < a.length; i++) {
		if (a[i].comments) {
			comment = a[i].comments
			delete a[i].comments
		}
		a[0].comments = comment
	}
}

function isConst(a) {
	if (!a)
		return true
	switch (a.type) {
	case 'ArrayExpression':
		return !a.elements.length
	case 'Literal':
		return true
	case 'NewExpression':
		if (a.callee.type !== 'Identifier' || a.callee.name !== 'Map')
			return
		return !a.arguments.length
	case 'ObjectExpression':
		return !a.properties.length
	}
}

function isConstVar(a) {
	if (a.type !== 'VariableDeclaration')
		return
	if (a.declarations.length !== 1)
		return
	return isConst(a.declarations[0].init)
}

function isExport(a) {
	if (a.type !== 'ExpressionStatement')
		return
	a = a.expression
	if (a.type !== 'AssignmentExpression')
		return
	if (a.left.type !== 'MemberExpression')
		return
	if (a.left.object.type !== 'Identifier')
		return
	if (a.left.object.name !== 'exports')
		return
	if (a.right.type !== 'Identifier')
		return
	return true
}

function isRequire(a) {
	if (a.type !== 'VariableDeclaration')
		return
	if (a.declarations.length !== 1)
		return
	a = a.declarations[0].init
	if (!a)
		return
	if (a.type !== 'CallExpression')
		return
	if (a.callee.type !== 'Identifier')
		return
	if (a.callee.name !== 'require')
		return
	return true
}

function isTerminator(a) {
	switch (a.type) {
	case 'BreakStatement':
	case 'ContinueStatement':
	case 'ReturnStatement':
	case 'ThrowStatement':
		return true
	}
}

function last(a) {
	return a[a.length - 1]
}

function negate(f) {
	return a => !f(a)
}

function run(a) {
	// ===
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'BinaryExpression')
				return
			if (a.left.value !== null && a.right.value !== null)
				switch (a.operator) {
				case '!=':
					a.operator = '!=='
					break
				case '==':
					a.operator = '==='
					break
				}
		},
		keys,
	})

	// Braces
	estraverse.traverse(a, {
		enter(a) {
			switch (a.type) {
			case 'DoWhileStatement':
			case 'ForInStatement':
			case 'ForOfStatement':
			case 'ForStatement':
			case 'WhileStatement':
				a.body = unbrace(a.body)
				break
			case 'IfStatement':
				a.consequent = unbrace(a.consequent)
				a.alternate = unbrace(a.alternate)
				break
			}
		},
		keys,
	})

	// Break
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'SwitchStatement')
				return
			if (!a.cases.length)
				return
			var c = last(a.cases)
			if (hasTerminator(c))
				return
			c.consequent.push({
				loc: a.loc,
				type: 'BreakStatement',
			})
		},
		keys,
	})

	// Comments
	estraverse.traverse(a, {
		enter(a) {
			if (!a.comments)
				return
			for (var c of a.comments) {
				if (c.type !== 'Line')
					continue
				var s = c.value
				for (var i = 0; i < s.length; i++)
					if (s[i] !== ' ') {
						c.value = s.slice(0, i) + s[i].toUpperCase() + s.slice(i + 1)
						break
					}
			}
		},
		keys,
	})

	// Sort cases
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'SwitchStatement')
				return
			a.cases = sortElements(
				a.cases,
				c => true,
				(c, i) => a.cases[i - 1].consequent.length,
				cmpCases,
				b =>  {
					var consequent = []
					for (var c of b)
						if (c.consequent.length) {
							consequent = c.consequent
							c.consequent = []
						}
					last(b).consequent = consequent
				})
			a.cases = sortBlocks(a.cases, (c, i) => a.cases[i - 1].consequent.length && hasTerminator(a.cases[i - 1]), cmpCases)
		},
		keys,
	})

	// Sort exports
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isExport,
				negate(isExport),
				(a, b) =>  {
					function key(x) {
						return x.expression.right.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort functions
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				b => b.type === 'FunctionDeclaration',
				b => b.type !== 'FunctionDeclaration',
				(a, b) =>  {
					function key(x) {
						return x.id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort properties
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'ObjectExpression')
				return
			a.properties = sortElements(
				a.properties,
				b => true,
				b => false,
				(a, b) =>  {
					function key(x) {
						x = x.key
						switch (x.type) {
						case 'Identifier':
							return x.name
						case 'Literal':
							return x.value
						}
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort requires
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isRequire,
				negate(isRequire),
				(a, b) =>  {
					function key(x) {
						return x.declarations[0].id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort vars
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isConstVar,
				negate(isConstVar),
				(a, b) =>  {
					function key(x) {
						return x.declarations[0].id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})
}

function sortBlocks(a, isEnd, cmp) {
	var bs = blocks(a, isEnd)
	bs = bs.sort((x, y) => cmp(x[0], y[0]))
	return [].concat(...bs)
}

function sortElements(a, isSortableStart, isSortableEnd, cmp, post) {
	if (a.constructor !== Array)
		return a
	var r = []
	for (var i = 0; i < a.length;) {
		if (!isSortableStart(a[i], j)) {
			r.push(a[i++])
			continue
		}
		for (var j = i + 1; j < a.length; j++) {
			if (a[j].comments)
				break
			if (isSortableEnd(a[j], j))
				break
		}
		var b = a.slice(i, j).sort(cmp)
		hoistComments(b)
		if (post)
			post(b)
		r.push(...b)
		i = j
	}
	return r
}

function unbrace(a) {
	if (!a)
		return a
	if (a.type !== 'BlockStatement')
		return a
	switch (a.body.length) {
	case 0:
		return {
			type: 'EmptyStatement',
		}
	case 1:
		if (a.body[0].comments)
			break
		return a.body[0]
	}
	return a
}

exports.run = run
<commit_msg>assignment<commit_after>'use strict'
var estraverse = require('estraverse')

// Node type unknown to estraverse
var keys = {
	ParenthesizedExpression: ['expression'],
}

function blocks(a, isEnd) {
	var bs = []
	for (var i = 0; i < a.length;) {
		for (var j = i + 1; j < a.length; j++)
			if (isEnd(a[j], j))
				break
		bs.push(a.slice(i, j))
		i = j
	}
	return bs
}

function cmp(a, b) {
	if (a < b)
		return -1
	if (a > b)
		return 1
	return 0
}

function cmpCases(a, b) {
	function key(x) {
		x = x.test
		if (!x)
			return '\uffff'
		switch (x.type) {
		case 'Identifier':
			return x.name
		case 'Literal':
			return x.value
		}
	}

	return cmp(key(a), key(b))
}

function hasTerminator(c) {
	var a = c.consequent
	if (!a.length)
		return
	return isTerminator(last(a))
}

function hoistComments(a) {
	var comment
	for (var i = 0; i < a.length; i++) {
		if (a[i].comments) {
			comment = a[i].comments
			delete a[i].comments
		}
		a[0].comments = comment
	}
}

function isConst(a) {
	if (!a)
		return true
	switch (a.type) {
	case 'ArrayExpression':
		return !a.elements.length
	case 'Literal':
		return true
	case 'NewExpression':
		if (a.callee.type !== 'Identifier' || a.callee.name !== 'Map')
			return
		return !a.arguments.length
	case 'ObjectExpression':
		return !a.properties.length
	}
}

function isConstAssign(a) {
	if (a.type !== 'ExpressionStatement')
		return
	a = a.expression
	if (a.type !== 'AssignmentExpression')
		return
	if (a.left.type !== 'Identifier')
		return
	return isConst(a.right)
}

function isConstVar(a) {
	if (a.type !== 'VariableDeclaration')
		return
	if (a.declarations.length !== 1)
		return
	return isConst(a.declarations[0].init)
}

function isExport(a) {
	if (a.type !== 'ExpressionStatement')
		return
	a = a.expression
	if (a.type !== 'AssignmentExpression')
		return
	if (a.left.type !== 'MemberExpression')
		return
	if (a.left.object.type !== 'Identifier')
		return
	if (a.left.object.name !== 'exports')
		return
	if (a.right.type !== 'Identifier')
		return
	return true
}

function isRequire(a) {
	if (a.type !== 'VariableDeclaration')
		return
	if (a.declarations.length !== 1)
		return
	a = a.declarations[0].init
	if (!a)
		return
	if (a.type !== 'CallExpression')
		return
	if (a.callee.type !== 'Identifier')
		return
	if (a.callee.name !== 'require')
		return
	return true
}

function isTerminator(a) {
	switch (a.type) {
	case 'BreakStatement':
	case 'ContinueStatement':
	case 'ReturnStatement':
	case 'ThrowStatement':
		return true
	}
}

function last(a) {
	return a[a.length - 1]
}

function negate(f) {
	return a => !f(a)
}

function run(a) {
	// ===
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'BinaryExpression')
				return
			if (a.left.value !== null && a.right.value !== null)
				switch (a.operator) {
				case '!=':
					a.operator = '!=='
					break
				case '==':
					a.operator = '==='
					break
				}
		},
		keys,
	})

	// Braces
	estraverse.traverse(a, {
		enter(a) {
			switch (a.type) {
			case 'DoWhileStatement':
			case 'ForInStatement':
			case 'ForOfStatement':
			case 'ForStatement':
			case 'WhileStatement':
				a.body = unbrace(a.body)
				break
			case 'IfStatement':
				a.consequent = unbrace(a.consequent)
				a.alternate = unbrace(a.alternate)
				break
			}
		},
		keys,
	})

	// Break
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'SwitchStatement')
				return
			if (!a.cases.length)
				return
			var c = last(a.cases)
			if (hasTerminator(c))
				return
			c.consequent.push({
				loc: a.loc,
				type: 'BreakStatement',
			})
		},
		keys,
	})

	// Comments
	estraverse.traverse(a, {
		enter(a) {
			if (!a.comments)
				return
			for (var c of a.comments) {
				if (c.type !== 'Line')
					continue
				var s = c.value
				for (var i = 0; i < s.length; i++)
					if (s[i] !== ' ') {
						c.value = s.slice(0, i) + s[i].toUpperCase() + s.slice(i + 1)
						break
					}
			}
		},
		keys,
	})

	// Sort assignment
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isConstAssign,
				negate(isConstAssign),
				(a, b) =>  {
					function key(x) {
						return x.expression.left.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort cases
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'SwitchStatement')
				return
			a.cases = sortElements(
				a.cases,
				c => true,
				(c, i) => a.cases[i - 1].consequent.length,
				cmpCases,
				b =>  {
					var consequent = []
					for (var c of b)
						if (c.consequent.length) {
							consequent = c.consequent
							c.consequent = []
						}
					last(b).consequent = consequent
				})
			a.cases = sortBlocks(a.cases, (c, i) => a.cases[i - 1].consequent.length && hasTerminator(a.cases[i - 1]), cmpCases)
		},
		keys,
	})

	// Sort exports
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isExport,
				negate(isExport),
				(a, b) =>  {
					function key(x) {
						return x.expression.right.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort functions
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				b => b.type === 'FunctionDeclaration',
				b => b.type !== 'FunctionDeclaration',
				(a, b) =>  {
					function key(x) {
						return x.id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort properties
	estraverse.traverse(a, {
		enter(a) {
			if (a.type !== 'ObjectExpression')
				return
			a.properties = sortElements(
				a.properties,
				b => true,
				b => false,
				(a, b) =>  {
					function key(x) {
						x = x.key
						switch (x.type) {
						case 'Identifier':
							return x.name
						case 'Literal':
							return x.value
						}
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort requires
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isRequire,
				negate(isRequire),
				(a, b) =>  {
					function key(x) {
						return x.declarations[0].id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})

	// Sort vars
	estraverse.traverse(a, {
		enter(a) {
			if (!a.body)
				return
			a.body = sortElements(
				a.body,
				isConstVar,
				negate(isConstVar),
				(a, b) =>  {
					function key(x) {
						return x.declarations[0].id.name
					}

					return cmp(key(a), key(b))
				})
		},
		keys,
	})
}

function sortBlocks(a, isEnd, cmp) {
	var bs = blocks(a, isEnd)
	bs = bs.sort((x, y) => cmp(x[0], y[0]))
	return [].concat(...bs)
}

function sortElements(a, isSortableStart, isSortableEnd, cmp, post) {
	if (a.constructor !== Array)
		return a
	var r = []
	for (var i = 0; i < a.length;) {
		if (!isSortableStart(a[i], j)) {
			r.push(a[i++])
			continue
		}
		for (var j = i + 1; j < a.length; j++) {
			if (a[j].comments)
				break
			if (isSortableEnd(a[j], j))
				break
		}
		var b = a.slice(i, j).sort(cmp)
		hoistComments(b)
		if (post)
			post(b)
		r.push(...b)
		i = j
	}
	return r
}

function unbrace(a) {
	if (!a)
		return a
	if (a.type !== 'BlockStatement')
		return a
	switch (a.body.length) {
	case 0:
		return {
			type: 'EmptyStatement',
		}
	case 1:
		if (a.body[0].comments)
			break
		return a.body[0]
	}
	return a
}

exports.run = run
<|endoftext|>


<commit_before>var assert = require("assert");
var types = require("./types");
var Type = types.Type;
var namedTypes = types.namedTypes;
var Node = namedTypes.Node;
var isArray = types.builtInTypes.array;
var hasOwn = Object.prototype.hasOwnProperty;

function Scope(path, parentScope) {
    assert.ok(this instanceof Scope);
    assert.ok(path instanceof require("./node-path"));
    ScopeType.assert(path.value);

    var depth;

    if (parentScope) {
        assert.ok(parentScope instanceof Scope);
        depth = parentScope.depth + 1;
    } else {
        parentScope = null;
        depth = 0;
    }

    Object.defineProperties(this, {
        path: { value: path },
        node: { value: path.value },
        isGlobal: { value: !parentScope, enumerable: true },
        depth: { value: depth },
        parent: { value: parentScope },
        bindings: { value: {} }
    });
}

var scopeTypes = [
    // Program nodes introduce global scopes.
    namedTypes.Program,

    // Function is the supertype of FunctionExpression,
    // FunctionDeclaration, ArrowExpression, etc.
    namedTypes.Function,

    // In case you didn't know, the caught parameter shadows any variable
    // of the same name in an outer scope.
    namedTypes.CatchClause
];

if (namedTypes.ModuleDeclaration) {
    // Include ModuleDeclaration only if it exists (ES6).
    scopeTypes.push(namedTypes.ModuleDeclaration);
}

var ScopeType = Type.or.apply(Type, scopeTypes);

Scope.isEstablishedBy = function(node) {
    return ScopeType.check(node);
};

var Sp = Scope.prototype;

// Will be overridden after an instance lazily calls scanScope.
Sp.didScan = false;

Sp.declares = function(name) {
    if (!this.didScan) {
        for (var name in this.bindings) {
            // Empty out this.bindings, just in cases.
            delete this.bindings[name];
        }
        scanScope(this.path, this.bindings);
        this.didScan = true;
    }

    return hasOwn.call(this.bindings, name);
};

function scanScope(path, bindings) {
    var node = path.value;
    ScopeType.assert(node);

    if (namedTypes.CatchClause.check(node)) {
        // A catch clause establishes a new scope but the only variable
        // bound in that scope is the catch parameter. Any other
        // declarations create bindings in the outer scope.
        addPattern(node.param, bindings);

    } else {
        recursiveScanScope(path, bindings);
    }
}

function recursiveScanScope(path, bindings) {
    var node = path.value;

    if (isArray.check(node)) {
        path.each(function(childPath) {
            recursiveScanChild(childPath, bindings);
        });

    } else if (namedTypes.Function.check(node)) {
        node.params.map(function(param) {
            addPattern(param, bindings);
        });

        recursiveScanChild(path.get("body"), bindings);

    } else if (namedTypes.VariableDeclarator.check(node)) {
        addPattern(node.id, bindings);
        recursiveScanChild(path.get("init"), bindings);

    } else if (namedTypes.ImportSpecifier &&
               namedTypes.ImportSpecifier.check(node)) {
        addPattern(node.name || node.id);

    } else if (Node.check(node)) {
        types.eachField(node, function(name, child) {
            var childPath = path.get(name);
            assert.strictEqual(childPath.value, child);
            recursiveScanChild(childPath, bindings);
        });
    }
}

function recursiveScanChild(path, bindings) {
    var node = path.value;

    if (namedTypes.FunctionDeclaration.check(node)) {
        addPattern(node.id, bindings);

    } else if (namedTypes.ClassDeclaration &&
               namedTypes.ClassDeclaration.check(node)) {
        addPattern(node.id, bindings);

    } else if (Scope.isEstablishedBy(node)) {
        if (namedTypes.CatchClause.check(node)) {
            var catchParamName = node.param.name;
            var hadBinding = hasOwn.call(bindings, catchParamName);

            // Any declarations that occur inside the catch body that do
            // not have the same name as the catch parameter should count
            // as bindings in the outer scope.
            recursiveScanScope(path.get("body"), bindings);

            // If a new binding matching the catch parameter name was
            // created while scanning the catch body, ignore it because it
            // actually refers to the catch parameter and not the outer
            // scope that we're currently scanning.
            if (!hadBinding) {
                delete bindings[catchParamName];
            }
        }

    } else {
        recursiveScanScope(path, bindings);
    }
}

function addPattern(pattern, bindings) {
    namedTypes.Pattern.assert(pattern);

    if (namedTypes.Identifier.check(pattern)) {
        bindings[pattern.name] = pattern;
    } else if (namedTypes.SpreadElement &&
               namedTypes.SpreadElement.check(pattern)) {
        addPattern(pattern.argument, bindings);
    }
}

Sp.lookup = function(name) {
    for (var scope = this; scope; scope = scope.parent)
        if (scope.declares(name))
            break;
    return scope;
};

Sp.getGlobalScope = function() {
    var scope = this;
    while (!scope.isGlobal)
        scope = scope.parent;
    return scope;
};

module.exports = Scope;
<commit_msg>Store lists of paths to patterns in the scope.bindings object.<commit_after>var assert = require("assert");
var types = require("./types");
var Type = types.Type;
var namedTypes = types.namedTypes;
var Node = namedTypes.Node;
var isArray = types.builtInTypes.array;
var hasOwn = Object.prototype.hasOwnProperty;

function Scope(path, parentScope) {
    assert.ok(this instanceof Scope);
    assert.ok(path instanceof require("./node-path"));
    ScopeType.assert(path.value);

    var depth;

    if (parentScope) {
        assert.ok(parentScope instanceof Scope);
        depth = parentScope.depth + 1;
    } else {
        parentScope = null;
        depth = 0;
    }

    Object.defineProperties(this, {
        path: { value: path },
        node: { value: path.value },
        isGlobal: { value: !parentScope, enumerable: true },
        depth: { value: depth },
        parent: { value: parentScope },
        bindings: { value: {} }
    });
}

var scopeTypes = [
    // Program nodes introduce global scopes.
    namedTypes.Program,

    // Function is the supertype of FunctionExpression,
    // FunctionDeclaration, ArrowExpression, etc.
    namedTypes.Function,

    // In case you didn't know, the caught parameter shadows any variable
    // of the same name in an outer scope.
    namedTypes.CatchClause
];

if (namedTypes.ModuleDeclaration) {
    // Include ModuleDeclaration only if it exists (ES6).
    scopeTypes.push(namedTypes.ModuleDeclaration);
}

var ScopeType = Type.or.apply(Type, scopeTypes);

Scope.isEstablishedBy = function(node) {
    return ScopeType.check(node);
};

var Sp = Scope.prototype;

// Will be overridden after an instance lazily calls scanScope.
Sp.didScan = false;

Sp.declares = function(name) {
    if (!this.didScan) {
        for (var name in this.bindings) {
            // Empty out this.bindings, just in cases.
            delete this.bindings[name];
        }
        scanScope(this.path, this.bindings);
        this.didScan = true;
    }

    return hasOwn.call(this.bindings, name);
};

function scanScope(path, bindings) {
    var node = path.value;
    ScopeType.assert(node);

    if (namedTypes.CatchClause.check(node)) {
        // A catch clause establishes a new scope but the only variable
        // bound in that scope is the catch parameter. Any other
        // declarations create bindings in the outer scope.
        addPattern(path.get("param"), bindings);

    } else {
        recursiveScanScope(path, bindings);
    }
}

function recursiveScanScope(path, bindings) {
    var node = path.value;

    if (isArray.check(node)) {
        path.each(function(childPath) {
            recursiveScanChild(childPath, bindings);
        });

    } else if (namedTypes.Function.check(node)) {
        path.get("params").each(function(paramPath) {
            addPattern(paramPath, bindings);
        });

        recursiveScanChild(path.get("body"), bindings);

    } else if (namedTypes.VariableDeclarator.check(node)) {
        addPattern(path.get("id"), bindings);
        recursiveScanChild(path.get("init"), bindings);

    } else if (namedTypes.ImportSpecifier &&
               namedTypes.ImportSpecifier.check(node)) {
        addPattern(node.name ? path.get("name") : path.get("id"));

    } else if (Node.check(node)) {
        types.eachField(node, function(name, child) {
            var childPath = path.get(name);
            assert.strictEqual(childPath.value, child);
            recursiveScanChild(childPath, bindings);
        });
    }
}

function recursiveScanChild(path, bindings) {
    var node = path.value;

    if (namedTypes.FunctionDeclaration.check(node)) {
        addPattern(path.get("id"), bindings);

    } else if (namedTypes.ClassDeclaration &&
               namedTypes.ClassDeclaration.check(node)) {
        addPattern(path.get("id"), bindings);

    } else if (Scope.isEstablishedBy(node)) {
        if (namedTypes.CatchClause.check(node)) {
            var catchParamName = node.param.name;
            var hadBinding = hasOwn.call(bindings, catchParamName);

            // Any declarations that occur inside the catch body that do
            // not have the same name as the catch parameter should count
            // as bindings in the outer scope.
            recursiveScanScope(path.get("body"), bindings);

            // If a new binding matching the catch parameter name was
            // created while scanning the catch body, ignore it because it
            // actually refers to the catch parameter and not the outer
            // scope that we're currently scanning.
            if (!hadBinding) {
                delete bindings[catchParamName];
            }
        }

    } else {
        recursiveScanScope(path, bindings);
    }
}

function addPattern(patternPath, bindings) {
    var pattern = patternPath.value;
    namedTypes.Pattern.assert(pattern);

    if (namedTypes.Identifier.check(pattern)) {
        if (hasOwn.call(bindings, pattern.name)) {
            bindings[pattern.name].push(patternPath);
        } else {
            bindings[pattern.name] = [patternPath];
        }

    } else if (namedTypes.SpreadElement &&
               namedTypes.SpreadElement.check(pattern)) {
        addPattern(patternPath.get("argument"), bindings);
    }
}

Sp.lookup = function(name) {
    for (var scope = this; scope; scope = scope.parent)
        if (scope.declares(name))
            break;
    return scope;
};

Sp.getGlobalScope = function() {
    var scope = this;
    while (!scope.isGlobal)
        scope = scope.parent;
    return scope;
};

module.exports = Scope;
<|endoftext|>


<commit_before>var express = require("express"),
    gulp = require("gulp"),
    http = require("http"),
    ecstatic = require("ecstatic");

module.exports = function(taskName, serverPort, subdirectory) {
    if (taskName === undefined) {
        taskName = "serve";
    }
    if (serverPort === undefined) {
        serverPort = 5050;
    }
    if (subdirectory === undefined) {
        subdirectory = "public";
    }
    var app = express();
    app.use(express.static(__dirname + '/../' + subdirectory));
    app.use("/lib", express.static(__dirname + '/../bower_components'));

    return function() {
        app.listen(serverPort);
    };
};
<commit_msg>serve fix<commit_after>var express = require("express"),
    gulp = require("gulp"),
    http = require("http"),
    ecstatic = require("ecstatic");

module.exports = function(taskName, serverPort, subdirectory) {
    if (taskName === undefined) {
        taskName = "serve";
    }
    if (serverPort === undefined) {
        serverPort = 5050;
    }
    if (subdirectory === undefined) {
        subdirectory = "public";
    }
    var app = express();
    app.use(express.static('./' + subdirectory));
    app.use("/lib", express.static('./bower_components'));

    return function() {
        app.listen(serverPort);
    };
};
<|endoftext|>


<commit_before>var pwm = require("pwm");

// Calling export with a chip number and a pin number will export that
// header and return a pwm header instance
var pin = pwm.export(0, 40, function() {
    console.log("Ready!");
    pin.setPeriod(1000, function() {
        var run = function() {
            var i = 1000;
            pin.setDutyCycle(i, function() {
                if (i >= 100) {
                    i -= 100;
                    setTimeout(run, 1000);
                } else {
                    console.log("finish");
                }
            });
        }
        run();
    });
});<commit_msg>servo test<commit_after>var raspi = require('raspi');
var PWM = require('raspi-pwm').PWM;

raspi.init(function() {
    var pwm = new PWM("GPIO21");
    pwm.write(72); // Center a servo
});<|endoftext|>


<commit_before>(typeof exports !== "undefined" ? exports : window).travisCov = (function(){
    var main = {
      check: function(cov,userOptions){
        var options = {
          threshold: 50, //defaults to 50%
          global: true,
          local: false
        };

        if (userOptions){
          options.threshold = userOptions.threshold || options.threshold;
          options.threshold = userOptions.global || options.global;
          options.threshold = userOptions.local || options.local;
        }

        var totals =[];
        for (var filename in cov) {
          var data = cov[filename];
          this.reportFile( data,options);
        }
        var totalHits = 0;
        var totalSloc = 0;
        totals.forEach(function(elem){
          totalHits += elem[0];
          totalSloc += elem[1];
        });
        var globCoverage = totalHits / totalSloc * 100;
        if (options.global && globCoverage < options.threshold){
          console.log("Code coverage below threshold: "+globCoverage+ " < "+options.threshold);
          process.exit(1);
        }
      },
      reportFile: function( data,options) {
        var ret = {
          coverage: 0,
          hits: 0,
          misses: 0,
          sloc: 0
        };
        data.source.forEach(function(line, num){
          num++;
          if (data[num] === 0) {
            ret.misses++;
            ret.sloc++;
          } else if (data[num] !== undefined) {
            ret.hits++;
            ret.sloc++;
          }
        });
        ret.coverage = ret.hits / ret.sloc * 100;

        if (options.local && ret.coverage < options.threshold){
          console.log("Code coverage below threshold: "+ret.coverage+ " < "+options.threshold);
          process.exit(1);
        }
        return [ret.hits,ret.sloc];

      }
  };
  return main;
})();<commit_msg>Fixes<commit_after>(typeof exports !== "undefined" ? exports : window).travisCov = (function(){
    var main = {
      check: function(cov,userOptions){
        var options = {
          threshold: 50, //defaults to 50%
          global: true,
          local: false
        };

        if (userOptions){
          options.threshold = userOptions.threshold || options.threshold;
          options.threshold = userOptions.global || options.global;
          options.threshold = userOptions.local || options.local;
        }

        var totals =[];
        for (var filename in cov) {
          var data = cov[filename];
          totals = this.reportFile( data,options);
        }
        var totalHits = 0;
        var totalSloc = 0;
        totals.forEach(function(elem){
          totalHits += elem[0];
          totalSloc += elem[1];
        });
        var globCoverage = totalHits / totalSloc * 100;
        console.log("global coverage:"+globCoverage);
        if (options.global && (globCoverage < options.threshold || isNaN(globCoverage))){
          console.log("Code coverage below threshold: "+globCoverage+ " < "+options.threshold);
          if (typeof process !== "undefined"){
            process.exit(1);
          }
          return false;

        }
        return true;
      },
      reportFile: function( data,options) {
        var ret = {
          coverage: 0,
          hits: 0,
          misses: 0,
          sloc: 0
        };
        data.source.forEach(function(line, num){
          num++;
          if (data[num] === 0) {
            ret.misses++;
            ret.sloc++;
          } else if (data[num] !== undefined) {
            ret.hits++;
            ret.sloc++;
          }
        });
        ret.coverage = ret.hits / ret.sloc * 100;

        if (options.local && ret.coverage < options.threshold){
          console.log("Code coverage below threshold: "+ret.coverage+ " < "+options.threshold);
          if (typeof process !== "undefined"){
            process.exit(1);
          }
          //need to figure out
        }
        return [ret.hits,ret.sloc];

      }
  };
  return main;
})();<|endoftext|>


<commit_before>/*
 * node-siege
 * https://github.com/npr/node-siege
 *
 * Copyright (c) 2012 johnymonster
 * Licensed under the MIT license.
 */
var exec = require('child_process').exec
  , async = require('async');

module.exports = function siege(options, cb) {
    var args = options;
    if(typeof options !== 'string') {
        args = optionsToString(options);
    }

    if(args !== false && args != '') {
        async.waterfall([
          exists,
          async.apply(run, args)
        ], function(err, results){
            cb(err,results);
        });
    } else {
        cb(new Error('Unable to parse options'));
    }
};

function exists(cb) {
    exec('which siege', function(error, stdout, stderr){
        if(error) {
            console.error('please install siege. http://www.joedog.org/siege-home/');
        }
        cb(error);
    })
}

function run(args, cb) {
    exec('siege ' + args, function(error, stdout, stderr){
        cb(error, stderr, stdout);
    });
}

/**
 * At some point allow for an object of options
 * currently not needed for this project
 * @param options
 */
function optionsToString(options) {
    return false;
}<commit_msg>Updating callback to return stderr and stdout.<commit_after>/*
 * node-siege
 * https://github.com/npr/node-siege
 *
 * Copyright (c) 2012 johnymonster
 * Licensed under the MIT license.
 */
var exec = require('child_process').exec
  , async = require('async');

module.exports = function siege(options, cb) {
    var args = options;
    if(typeof options !== 'string') {
        args = optionsToString(options);
    }

    if(args !== false && args != '') {
        async.waterfall([
          exists,
          async.apply(run, args)
        ], function(err, stderr, stdout){
            cb(err,stderr, stdout);
        });
    } else {
        cb(new Error('Unable to parse options'));
    }
};

function exists(cb) {
    exec('which siege', function(error, stdout, stderr){
        if(error) {
            console.error('please install siege. http://www.joedog.org/siege-home/');
        }
        cb(error);
    })
}

function run(args, cb) {
    exec('siege ' + args, function(error, stdout, stderr){
        cb(error, stderr, stdout);
    });
}

/**
 * At some point allow for an object of options
 * currently not needed for this project
 * @param options
 */
function optionsToString(options) {
    return false;
}<|endoftext|>


<commit_before>var fs = require("fs");
var ejs = require("ejs");
var uuid = require("node-uuid");
var when = require("when");
var bResources = require("buster-resources");
var bResourcesResourceSet = bResources.resourceSet;

var templates = {
    capturedBrowser: fs.readFileSync(__dirname + "/templates/captured_browser.html", "utf8")
};

var frameworkScriptPaths = [
    require.resolve("./../vendor/json/json2"),
    require.resolve("buster-core"),
    require.resolve("buster-core").replace("buster-core.js", "buster-event-emitter.js"),
    require.resolve("faye/faye-browser-min"),
];
var slaveScriptPaths = [
    require.resolve("./browser/cross-browser-util"),
    require.resolve("./browser/session-loader"),
    require.resolve("./browser/session-loader-init")
];
var buster = require("buster-core");

exports.create = function (server, bayeuxServer, resourcesMiddleware, currentSession) {
    var bayeuxClient = server.bayeux;
    var ended = false;
    var bayeuxDisconnectListener;
    var isReady;
    var bayeuxClientId;
    var headerHeight;
    var headerResourceSet;
    var headerPath;

    var slave = buster.extend(buster.eventEmitter.create(), {
        header: function (height, resourceSet) {
            resourcesMiddleware.unmount(headerPath);

            // Unset
            if (height == undefined) return;

            // Set
            headerHeight = height;
            headerResourceSet = resourceSet;
            resourcesMiddleware.mount(headerPath, resourceSet);
        },

        startSession: function (session) {
            this.sessionInProgress = true;
            session.on("end", endSession);
            currentSession = session;
            broadcastSession();
        },

        // Note: when changing this, make sure browser/control-frame.js still
        // works. It's not currently integration tested.
        getEnv: function() {
            var env = {
                slaveId: this.id,
                bayeuxPath: server.messagingContextPath,
                capturePath: server.capturePath
            };

            return buster.extend(env, this.env);
        },

        serialize: function () {
            return {
                id: this.id,
                url: this.url,
                headerPath: headerPath
            };
        }
    });

    slave.id = uuid();
    var baseUrl = "/slaves/" + slave.id;
    slave.url = baseUrl + "/browser"
    slave.env = {};

    headerPath = baseUrl + "/header";
    bayeuxDisconnectListener = function (_bayeuxClientId) {
        if (bayeuxClientId == _bayeuxClientId) endSlave();
    };

    function ready(_bayeuxClientId) {
        isReady = true;
        bayeuxClientId = _bayeuxClientId;
        broadcastSession();
        slave.emit("ready");
    }

    function broadcastSession() {
        if (currentSession !== undefined && isReady) {
            bayeuxClient.publish("/" + slave.id + "/session/start", currentSession.toJSON());

            var session = currentSession;
            var readyEvent = "/" + slave.id + "/session/" + currentSession.id + "/ready";
            var sessionReadyHandler = function () {
                slave.emit("sessionLoaded", session);
                bayeuxClient.unsubscribe(readyEvent, sessionReadyHandler);
            };
            bayeuxClient.subscribe(readyEvent, sessionReadyHandler);
        }
    }

    function endSession() {
        slave.sessionInProgress = false;
        bayeuxClient.publish("/" + slave.id + "/session/end", {});
        currentSession = undefined;
    }

    function endSlave() {
        if (ended) return;
        ended = true;

        bayeuxServer.unbind("disconnect", bayeuxDisconnectListener);
        slave.emit("end");
    }

    function loadFileInResourceSet(path) {
        resourceSet.addFileResource(path);
        resourceSet.appendLoad(path);
    }

    var resourceSet = bResourcesResourceSet.create();
    resourceSet.addResource({
        path: "/",
        content: function () {
            var locals = {};
            locals.slaveRoot = this.url;
            locals.scripts = resourceSet.loadPath.paths();
            locals.hasHeaderFrame = (headerResourceSet !== undefined);
            if (locals.hasHeaderFrame) {
                locals.headerFrameHeight = headerHeight;
                locals.headerFramePath = headerPath;
            }

            return ejs.render(templates.capturedBrowser, {locals: locals});
        }
    });

    frameworkScriptPaths.forEach(loadFileInResourceSet);
    resourceSet.addResource("/env.js", {
        content: function (promise, req) {
            promise.resolve("buster.env = " + JSON.stringify(slave.getEnv()) + ";");
        }
    });
    resourceSet.appendLoad("/env.js");
    slaveScriptPaths.forEach(loadFileInResourceSet);

    bayeuxClient.subscribe("/" + slave.id + "/ready", ready);
    bayeuxServer.bind("disconnect", bayeuxDisconnectListener);

    if (currentSession && !(currentSession.joinable == false)) {
        slave.startSession(currentSession);
    }

    resourcesMiddleware.mount(slave.url, resourceSet);

    return slave;
};<commit_msg>The attribute headerPath is never used.<commit_after>var fs = require("fs");
var ejs = require("ejs");
var uuid = require("node-uuid");
var when = require("when");
var bResources = require("buster-resources");
var bResourcesResourceSet = bResources.resourceSet;

var templates = {
    capturedBrowser: fs.readFileSync(__dirname + "/templates/captured_browser.html", "utf8")
};

var frameworkScriptPaths = [
    require.resolve("./../vendor/json/json2"),
    require.resolve("buster-core"),
    require.resolve("buster-core").replace("buster-core.js", "buster-event-emitter.js"),
    require.resolve("faye/faye-browser-min"),
];
var slaveScriptPaths = [
    require.resolve("./browser/cross-browser-util"),
    require.resolve("./browser/session-loader"),
    require.resolve("./browser/session-loader-init")
];
var buster = require("buster-core");

exports.create = function (server, bayeuxServer, resourcesMiddleware, currentSession) {
    var bayeuxClient = server.bayeux;
    var ended = false;
    var bayeuxDisconnectListener;
    var isReady;
    var bayeuxClientId;
    var headerHeight;
    var headerResourceSet;
    var headerPath;

    var slave = buster.extend(buster.eventEmitter.create(), {
        header: function (height, resourceSet) {
            resourcesMiddleware.unmount(headerPath);

            // Unset
            if (height == undefined) return;

            // Set
            headerHeight = height;
            headerResourceSet = resourceSet;
            resourcesMiddleware.mount(headerPath, resourceSet);
        },

        startSession: function (session) {
            this.sessionInProgress = true;
            session.on("end", endSession);
            currentSession = session;
            broadcastSession();
        },

        // Note: when changing this, make sure browser/control-frame.js still
        // works. It's not currently integration tested.
        getEnv: function() {
            var env = {
                slaveId: this.id,
                bayeuxPath: server.messagingContextPath,
                capturePath: server.capturePath
            };

            return buster.extend(env, this.env);
        },

        serialize: function () {
            return {
                id: this.id,
                url: this.url
            };
        }
    });

    slave.id = uuid();
    var baseUrl = "/slaves/" + slave.id;
    slave.url = baseUrl + "/browser"
    slave.env = {};

    headerPath = baseUrl + "/header";
    bayeuxDisconnectListener = function (_bayeuxClientId) {
        if (bayeuxClientId == _bayeuxClientId) endSlave();
    };

    function ready(_bayeuxClientId) {
        isReady = true;
        bayeuxClientId = _bayeuxClientId;
        broadcastSession();
        slave.emit("ready");
    }

    function broadcastSession() {
        if (currentSession !== undefined && isReady) {
            bayeuxClient.publish("/" + slave.id + "/session/start", currentSession.toJSON());

            var session = currentSession;
            var readyEvent = "/" + slave.id + "/session/" + currentSession.id + "/ready";
            var sessionReadyHandler = function () {
                slave.emit("sessionLoaded", session);
                bayeuxClient.unsubscribe(readyEvent, sessionReadyHandler);
            };
            bayeuxClient.subscribe(readyEvent, sessionReadyHandler);
        }
    }

    function endSession() {
        slave.sessionInProgress = false;
        bayeuxClient.publish("/" + slave.id + "/session/end", {});
        currentSession = undefined;
    }

    function endSlave() {
        if (ended) return;
        ended = true;

        bayeuxServer.unbind("disconnect", bayeuxDisconnectListener);
        slave.emit("end");
    }

    function loadFileInResourceSet(path) {
        resourceSet.addFileResource(path);
        resourceSet.appendLoad(path);
    }

    var resourceSet = bResourcesResourceSet.create();
    resourceSet.addResource({
        path: "/",
        content: function () {
            var locals = {};
            locals.slaveRoot = this.url;
            locals.scripts = resourceSet.loadPath.paths();
            locals.hasHeaderFrame = (headerResourceSet !== undefined);
            if (locals.hasHeaderFrame) {
                locals.headerFrameHeight = headerHeight;
                locals.headerFramePath = headerPath;
            }

            return ejs.render(templates.capturedBrowser, {locals: locals});
        }
    });

    frameworkScriptPaths.forEach(loadFileInResourceSet);
    resourceSet.addResource("/env.js", {
        content: function (promise, req) {
            promise.resolve("buster.env = " + JSON.stringify(slave.getEnv()) + ";");
        }
    });
    resourceSet.appendLoad("/env.js");
    slaveScriptPaths.forEach(loadFileInResourceSet);

    bayeuxClient.subscribe("/" + slave.id + "/ready", ready);
    bayeuxServer.bind("disconnect", bayeuxDisconnectListener);

    if (currentSession && !(currentSession.joinable == false)) {
        slave.startSession(currentSession);
    }

    resourcesMiddleware.mount(slave.url, resourceSet);

    return slave;
};<|endoftext|>


<commit_before>'use strict'

const osc = require('osc')
const path = require('path')
const { args, config, log } = require(path.join(__dirname, '..', 'main.config.js'))

let isOpen = false
const udpPort = new osc.UDPPort({
  // SEE https://github.com/colinbdclark/osc.js/issues/83#issuecomment-290567155
  localAddress: config.sound.udp.local,
  remoteAddress: config.sound.udp.remote,
  remotePort: config.sound.udp.port,
  metadata: true
})

udpPort.on('ready', () => {
  isOpen = true
  log.info('Sound UDP is ready on port ' + config.sound.udp.port)
})

udpPort.on('error', (err) => {
  isOpen = false
  log.error(err)
})

args.sound && udpPort.open()

function findType (value) {
  const isInt = n => n % 1 === 0
  return isInt(value) ? 'i' : 'f'
}

module.exports = {
  send: (address, values = [0]) => {
    if (isOpen) {
      /**
       * message = {
       *   address: '/varName',
       *   args: [
       *     { type: 'i', value: 100 }
       *     { type: 'f', value: 1.0 }
       *   ]
       * }
       */
      values = Array.isArray(values) ? values : [values]
      udpPort.send({
        address,
        args: values.map(value => {
          return { value, type: findType(value) }
        })
      })
    }
  }
}
<commit_msg>[sound] Add method to determine if sound is enabled<commit_after>'use strict'

const osc = require('osc')
const path = require('path')
const { args, config, log } = require(path.join(__dirname, '..', 'main.config.js'))

let isOpen = false
const udpPort = new osc.UDPPort({
  // SEE https://github.com/colinbdclark/osc.js/issues/83#issuecomment-290567155
  localAddress: config.sound.udp.local,
  remoteAddress: config.sound.udp.remote,
  remotePort: config.sound.udp.port,
  metadata: true
})

udpPort.on('ready', () => {
  isOpen = true
  log.info('Sound UDP is ready on port ' + config.sound.udp.port)
})

udpPort.on('error', (err) => {
  isOpen = false
  log.error(err)
})

args.sound && udpPort.open()

function findType (value) {
  const isInt = n => n % 1 === 0
  return isInt(value) ? 'i' : 'f'
}

module.exports = {
  enabled: (args.sound === true),
  send: (address, values = [0]) => {
    if (isOpen) {
      /**
       * message = {
       *   address: '/varName',
       *   args: [
       *     { type: 'i', value: 100 }
       *     { type: 'f', value: 1.0 }
       *   ]
       * }
       */
      values = Array.isArray(values) ? values : [values]
      udpPort.send({
        address,
        args: values.map(value => {
          return { value, type: findType(value) }
        })
      })
    }
  }
}
<|endoftext|>