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

class ReactSplitGrid extends React.Component {
    constructor(props) {
        super(props)

        this.columnGutters = {}
        this.rowGutters = {}

        this.state = {
            gridTemplateColumns: props.gridTemplateColumns
                ? props.gridTemplateColumns
                : null,
            gridTemplateRows: props.gridTemplateRows
                ? props.gridTemplateRows
                : null,
        }

        this.getGridProps = this.getGridProps.bind(this)
        this.getGutterProps = this.getGutterProps.bind(this)
        this.handleDragStart = this.handleDragStart.bind(this)
        this.writeStyle = this.writeStyle.bind(this)
        this.onDrag = this.onDrag.bind(this)
    }

    componentDidMount() {
        const { children, ...options } = this.props

        options.writeStyle = this.writeStyle
        options.onDrag = this.onDrag

        this.split = Split(options)
    }

    componentDidUpdate(prevProps) {
        const { columnMinSizes, rowMinSizes, children, ...options } = this.props

        const {
            columnMinSizes: prevColumnMinSizes,
            rowMinSizes: prevRowMinSizes,
        } = prevProps

        const otherProps = [
            'minSize',
            'columnMinSize',
            'rowMinSize',
            'columnMinSizes',
            'rowMinSizes',
            'snapOffset',
            'columnSnapOffset',
            'rowSnapOffset',
            'dragInterval',
            'columnDragInterval',
            'rowDragInterval',
            'cursor',
            'columnCursor',
            'rowCursor',
        ]

        let needsRecreate = otherProps
            // eslint-disable-next-line react/destructuring-assignment
            .map(prop => this.props[prop] !== prevProps[prop])
            .reduce((accum, same) => accum || same, false)

        // TODO use deep equals
        if (columnMinSizes !== prevColumnMinSizes) {
            needsRecreate = true
        }

        if (rowMinSizes !== prevRowMinSizes) {
            needsRecreate = true
        }

        // Destroy and re-create split if options changed
        if (needsRecreate) {
            options.columnMinSizes = columnMinSizes
            options.rowMinSizes = rowMinSizes

            this.split.destroy(false)

            this.split = Split(options)
        }
    }

    componentWillUnmount() {
        this.split.destroy()
        delete this.split
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        const state = {}
        let needsSetState = false

        if (
            nextProps.gridTemplateColumns &&
            nextProps.gridTemplateColumns !== prevState.gridTemplateColumns
        ) {
            state.gridTemplateColumns = nextProps.gridTemplateColumns
            needsSetState = true
        }

        if (
            nextProps.gridTemplateRows &&
            nextProps.gridTemplateRows !== prevState.prevGridTemplateRows
        ) {
            state.gridTemplateRows = nextProps.gridTemplateRows
            needsSetState = true
        }

        if (needsSetState) {
            return state
        }

        return null
    }

    onDrag(direction, track, style) {
        const { onDrag } = this.props

        if (onDrag) {
            onDrag(direction, track, style)
        }
    }

    getGridProps() {
        const { gridTemplateColumns, gridTemplateRows } = this.state
        const style = {}

        if (gridTemplateColumns) {
            style.gridTemplateColumns = gridTemplateColumns
        }

        if (gridTemplateRows) {
            style.gridTemplateRows = gridTemplateRows
        }

        return {
            style,
        }
    }

    getGutterProps(direction, track) {
        return {
            onMouseDown: this.handleDragStart(direction, track),
            onTouchStart: this.handleDragStart(direction, track),
        }
    }

    handleDragStart(direction, track) {
        return e => {
            this.split.handleDragStart(e, direction, track)
        }
    }

    writeStyle(element, gridTemplateProp, style) {
        const state = {}

        if (gridTemplateProp === 'grid-template-columns') {
            state.gridTemplateColumns = style
        } else if (gridTemplateProp === 'grid-template-rows') {
            state.gridTemplateRows = style
        }

        this.setState(state)
    }

    render() {
        const { component, render, children } = this.props
        const props = {
            getGridProps: this.getGridProps,
            getGutterProps: this.getGutterProps,
        }

        /* eslint-disable no-nested-ternary */
        return component
            ? React.createElement(component, props)
            : render
            ? render(props)
            : children
            ? typeof children === 'function'
                ? children(props)
                : !(React.Children.count(children) === 0)
                ? React.Chidren.only(children)
                : null
            : null
    }
}

ReactSplitGrid.propTypes = {
    component: PropTypes.element,
    render: PropTypes.func,
    children: PropTypes.element,
    gridTemplateColumns: PropTypes.string,
    gridTemplateRows: PropTypes.string,
    columnMinSizes: PropTypes.arrayOf(PropTypes.number),
    rowMinSizes: PropTypes.arrayOf(PropTypes.number),
    onDrag: PropTypes.func,
}

ReactSplitGrid.defaultProps = {
    component: undefined,
    render: undefined,
    children: undefined,
    gridTemplateColumns: undefined,
    gridTemplateRows: undefined,
    columnMinSizes: undefined,
    rowMinSizes: undefined,
    onDrag: undefined,
}

export default ReactSplitGrid
<commit_msg>fix react children typo<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import Split from 'split-grid'

class ReactSplitGrid extends React.Component {
    constructor(props) {
        super(props)

        this.columnGutters = {}
        this.rowGutters = {}

        this.state = {
            gridTemplateColumns: props.gridTemplateColumns
                ? props.gridTemplateColumns
                : null,
            gridTemplateRows: props.gridTemplateRows
                ? props.gridTemplateRows
                : null,
        }

        this.getGridProps = this.getGridProps.bind(this)
        this.getGutterProps = this.getGutterProps.bind(this)
        this.handleDragStart = this.handleDragStart.bind(this)
        this.writeStyle = this.writeStyle.bind(this)
        this.onDrag = this.onDrag.bind(this)
    }

    componentDidMount() {
        const { children, ...options } = this.props

        options.writeStyle = this.writeStyle
        options.onDrag = this.onDrag

        this.split = Split(options)
    }

    componentDidUpdate(prevProps) {
        const { columnMinSizes, rowMinSizes, children, ...options } = this.props

        const {
            columnMinSizes: prevColumnMinSizes,
            rowMinSizes: prevRowMinSizes,
        } = prevProps

        const otherProps = [
            'minSize',
            'columnMinSize',
            'rowMinSize',
            'columnMinSizes',
            'rowMinSizes',
            'snapOffset',
            'columnSnapOffset',
            'rowSnapOffset',
            'dragInterval',
            'columnDragInterval',
            'rowDragInterval',
            'cursor',
            'columnCursor',
            'rowCursor',
        ]

        let needsRecreate = otherProps
            // eslint-disable-next-line react/destructuring-assignment
            .map(prop => this.props[prop] !== prevProps[prop])
            .reduce((accum, same) => accum || same, false)

        // TODO use deep equals
        if (columnMinSizes !== prevColumnMinSizes) {
            needsRecreate = true
        }

        if (rowMinSizes !== prevRowMinSizes) {
            needsRecreate = true
        }

        // Destroy and re-create split if options changed
        if (needsRecreate) {
            options.columnMinSizes = columnMinSizes
            options.rowMinSizes = rowMinSizes

            this.split.destroy(false)

            this.split = Split(options)
        }
    }

    componentWillUnmount() {
        this.split.destroy()
        delete this.split
    }

    static getDerivedStateFromProps(nextProps, prevState) {
        const state = {}
        let needsSetState = false

        if (
            nextProps.gridTemplateColumns &&
            nextProps.gridTemplateColumns !== prevState.gridTemplateColumns
        ) {
            state.gridTemplateColumns = nextProps.gridTemplateColumns
            needsSetState = true
        }

        if (
            nextProps.gridTemplateRows &&
            nextProps.gridTemplateRows !== prevState.prevGridTemplateRows
        ) {
            state.gridTemplateRows = nextProps.gridTemplateRows
            needsSetState = true
        }

        if (needsSetState) {
            return state
        }

        return null
    }

    onDrag(direction, track, style) {
        const { onDrag } = this.props

        if (onDrag) {
            onDrag(direction, track, style)
        }
    }

    getGridProps() {
        const { gridTemplateColumns, gridTemplateRows } = this.state
        const style = {}

        if (gridTemplateColumns) {
            style.gridTemplateColumns = gridTemplateColumns
        }

        if (gridTemplateRows) {
            style.gridTemplateRows = gridTemplateRows
        }

        return {
            style,
        }
    }

    getGutterProps(direction, track) {
        return {
            onMouseDown: this.handleDragStart(direction, track),
            onTouchStart: this.handleDragStart(direction, track),
        }
    }

    handleDragStart(direction, track) {
        return e => {
            this.split.handleDragStart(e, direction, track)
        }
    }

    writeStyle(element, gridTemplateProp, style) {
        const state = {}

        if (gridTemplateProp === 'grid-template-columns') {
            state.gridTemplateColumns = style
        } else if (gridTemplateProp === 'grid-template-rows') {
            state.gridTemplateRows = style
        }

        this.setState(state)
    }

    render() {
        const { component, render, children } = this.props
        const props = {
            getGridProps: this.getGridProps,
            getGutterProps: this.getGutterProps,
        }

        /* eslint-disable no-nested-ternary */
        return component
            ? React.createElement(component, props)
            : render
            ? render(props)
            : children
            ? typeof children === 'function'
                ? children(props)
                : !(React.Children.count(children) === 0)
                ? React.Children.only(children)
                : null
            : null
    }
}

ReactSplitGrid.propTypes = {
    component: PropTypes.element,
    render: PropTypes.func,
    children: PropTypes.element,
    gridTemplateColumns: PropTypes.string,
    gridTemplateRows: PropTypes.string,
    columnMinSizes: PropTypes.arrayOf(PropTypes.number),
    rowMinSizes: PropTypes.arrayOf(PropTypes.number),
    onDrag: PropTypes.func,
}

ReactSplitGrid.defaultProps = {
    component: undefined,
    render: undefined,
    children: undefined,
    gridTemplateColumns: undefined,
    gridTemplateRows: undefined,
    columnMinSizes: undefined,
    rowMinSizes: undefined,
    onDrag: undefined,
}

export default ReactSplitGrid
<|endoftext|>


<commit_before>import isEqual from 'lodash/isEqual';
import React from 'react';
import {
  evaluateTransforms, mergePropPair
} from 'reactabular-utils';
import { tableBodyTypes, tableBodyContextTypes } from './types';

export default class Body extends React.Component {
  constructor(props) {
    super(props);

    this.ref = null;
  }
  shouldComponentUpdate(nextProps, nextState, nextContext) {
    // Skip checking props against `onRow` since that can be bound at render().
    // That's not particularly good practice but you never know how the users
    // prefer to define the handler.
    return !(isEqual(omitOnRow(this.props), omitOnRow(nextProps)) &&
      isEqual(this.context, nextContext));
  }
  render() {
    const { onRow, rows, rowKey, ...props } = this.props;
    const { bodyColumns, components } = this.context;

    props.ref = body => {
      this.ref = body;
    };

    return React.createElement(
      components.body.wrapper,
      props,
      rows.map((r, i) => {
        if (process.env.NODE_ENV !== 'production') {
          // Arrays cannot have rowKeys by definition so we have to go by index there.
          if (!Array.isArray(r) && !{}.hasOwnProperty.call(r, rowKey)) {
            console.warn( // eslint-disable-line no-console
              'Table.Body - Missing valid rowKey!',
              r,
              rowKey
            );
          }
        }

        return React.createElement(BodyRow, {
          key: `${r[rowKey] || i}-row`,
          components: components.body,
          row: r,
          rowProps: onRow(r, i),
          rowIndex: i,
          rowData: rows[i],
          columns: bodyColumns
        });
      })
    );
  }
  getRef() {
    return this.ref;
  }
}
Body.propTypes = tableBodyTypes;
Body.defaultProps = {
  onRow: () => {}
};
Body.contextTypes = tableBodyContextTypes;

function omitOnRow(props) {
  const { onRow, ...ret } = props; // eslint-disable-line no-unused-vars

  return ret;
}

class BodyRow extends React.Component {
  shouldComponentUpdate(nextProps) {
    const previousProps = this.props;

    return !(
      isEqual(previousProps.columns, nextProps.columns) &&
      isEqual(previousProps.row, nextProps.row) &&
      isEqual(previousProps.rowProps, nextProps.rowProps) &&
      isEqual(previousProps.rowData, nextProps.rowData)
    );
  }
  render() {
    const { columns, components, row, rowProps, rowIndex, rowData } = this.props;

    return React.createElement(
      components.row,
      rowProps,
      columns.map(({ column, cell, property, props }, j) => {
        const {
          transforms = [],
          format = a => a
        } = cell || {}; // TODO: test against this case
        const extraParameters = {
          columnIndex: j,
          column,
          rowData,
          rowIndex,
          property
        };
        const transformed = evaluateTransforms(transforms, row[property], extraParameters);

        if (!transformed) {
          console.warn('Table.Body - Failed to receive a transformed result'); // eslint-disable-line max-len, no-console
        }

        return React.createElement(
          components.cell,
          {
            key: `${j}-cell`,
            ...mergePropPair(props, transformed)
          },
          transformed.children || format(row[`_${property}`] || row[property], extraParameters)
        );
      })
    );
  }
}
BodyRow.propTypes = {
  columns: React.PropTypes.array.isRequired,
  components: React.PropTypes.object,
  row: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  rowProps: React.PropTypes.object,
  rowIndex: React.PropTypes.number.isRequired,
  rowData: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]).isRequired
};
<commit_msg>table - Push `onRow` check lower in the hierarchy<commit_after>import isEqual from 'lodash/isEqual';
import React from 'react';
import {
  evaluateTransforms, mergePropPair
} from 'reactabular-utils';
import { tableBodyTypes, tableBodyContextTypes } from './types';

export default class Body extends React.Component {
  constructor(props) {
    super(props);

    this.ref = null;
  }
  shouldComponentUpdate(nextProps, nextState, nextContext) {
    // Skip checking props against `onRow` since that can be bound at render().
    // That's not particularly good practice but you never know how the users
    // prefer to define the handler.
    return !(isEqual(omitOnRow(this.props), omitOnRow(nextProps)) &&
      isEqual(this.context, nextContext));
  }
  render() {
    const { onRow, rows, rowKey, ...props } = this.props;
    const { bodyColumns, components } = this.context;

    props.ref = body => {
      this.ref = body;
    };

    return React.createElement(
      components.body.wrapper,
      props,
      rows.map((r, i) => {
        if (process.env.NODE_ENV !== 'production') {
          // Arrays cannot have rowKeys by definition so we have to go by index there.
          if (!Array.isArray(r) && !{}.hasOwnProperty.call(r, rowKey)) {
            console.warn( // eslint-disable-line no-console
              'Table.Body - Missing valid rowKey!',
              r,
              rowKey
            );
          }
        }

        return React.createElement(BodyRow, {
          key: `${r[rowKey] || i}-row`,
          components: components.body,
          onRow,
          row: r,
          rowIndex: i,
          rowData: rows[i],
          columns: bodyColumns
        });
      })
    );
  }
  getRef() {
    return this.ref;
  }
}
Body.propTypes = tableBodyTypes;
Body.defaultProps = {
  onRow: () => {}
};
Body.contextTypes = tableBodyContextTypes;

function omitOnRow(props) {
  const { onRow, ...ret } = props; // eslint-disable-line no-unused-vars

  return ret;
}

class BodyRow extends React.Component {
  shouldComponentUpdate(nextProps) {
    const previousProps = this.props;

    return !(
      isEqual(previousProps.columns, nextProps.columns) &&
      isEqual(previousProps.row, nextProps.row) &&
      isEqual(previousProps.rowData, nextProps.rowData)
    );
  }
  render() {
    const { columns, components, row, onRow, rowIndex, rowData } = this.props;

    return React.createElement(
      components.row,
      onRow(row, rowIndex),
      columns.map(({ column, cell, property, props }, j) => {
        const {
          transforms = [],
          format = a => a
        } = cell || {}; // TODO: test against this case
        const extraParameters = {
          columnIndex: j,
          column,
          rowData,
          rowIndex,
          property
        };
        const transformed = evaluateTransforms(transforms, row[property], extraParameters);

        if (!transformed) {
          console.warn('Table.Body - Failed to receive a transformed result'); // eslint-disable-line max-len, no-console
        }

        return React.createElement(
          components.cell,
          {
            key: `${j}-cell`,
            ...mergePropPair(props, transformed)
          },
          transformed.children || format(row[`_${property}`] || row[property], extraParameters)
        );
      })
    );
  }
}
BodyRow.defaultProps = {
  onRow: () => ({})
};
BodyRow.propTypes = {
  columns: React.PropTypes.array.isRequired,
  components: React.PropTypes.object,
  row: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]),
  onRow: React.PropTypes.func,
  rowIndex: React.PropTypes.number.isRequired,
  rowData: React.PropTypes.oneOfType([
    React.PropTypes.array,
    React.PropTypes.object
  ]).isRequired
};
<|endoftext|>


<commit_before>'use strict';

var helpers = require('../helpers'),
    os = require('os');

module.exports = {
  'name': 'indentation',
  'defaults': {
    'size': 2
  },
  'detect': function (ast, parser) {
    var result = [];

    var processNode = function (node, level) {
      var i,
          n,
          space,
          spaceLength,
          count;

      level = level || 0;

      if (node.is('braces')) {
        return;
      }

      for (i = 0; i < node.length; i++) {
        n = node.get(i);

        if (!n) {
          continue;
        }

        if (n.type === 'space') {
          space = n.content.lastIndexOf(os.EOL);

          if (space >= 0) {
            spaceLength = n.content.slice(space + 1).length;

            try {
              count = n.content.slice(space + 1).match(/ /g).length;
            }
            catch (e) {
              count = 0;
            }

            if (spaceLength / parser.options.size !== level) {
              if (count !== spaceLength) {
                result = helpers.addUnique(result, {
                  'ruleId': parser.rule.name,
                  'line': node.content[i + 1].start.line,
                  'column': node.content[i + 1].start.column,
                  'message': 'Mixed tabs and spaces',
                  'severity': parser.severity
                });
              }
              if (i !== node.length - 1) {
                result = helpers.addUnique(result, {
                  'ruleId': parser.rule.name,
                  'line': node.content[i + 1].start.line,
                  'column': node.content[i + 1].start.column,
                  'message': 'Indentation of ' + spaceLength + ', expected ' + level * parser.options.size,
                  'severity': parser.severity
                });
              }
            }
          }
        }

        if (n.is('block') || n.is('atrulers') || (n.is('parentheses') && !node.is('atruleb'))) {
          level++;
        }

        processNode(n, level);
      }
    };

    processNode(ast);

    return result;
  }
};
<commit_msg>:bug: Indentation rule takes account of Windows line endings<commit_after>'use strict';

var helpers = require('../helpers');

module.exports = {
  'name': 'indentation',
  'defaults': {
    'size': 2
  },
  'detect': function (ast, parser) {
    var result = [];

    var processNode = function (node, level) {
      var i,
          n,
          space,
          spaceLength,
          count;

      level = level || 0;

      if (node.is('braces')) {
        return;
      }

      for (i = 0; i < node.length; i++) {
        n = node.get(i);

        if (!n) {
          continue;
        }

        if (n.type === 'space') {
          // Test for CRLF first, since it includes LF
          space = n.content.lastIndexOf('\r\n');

          if (space === -1) {
            space = n.content.lastIndexOf('\n');
          }

          if (space >= 0) {
            spaceLength = n.content.slice(space + 1).length;

            try {
              count = n.content.slice(space + 1).match(/ /g).length;
            }
            catch (e) {
              count = 0;
            }

            if (spaceLength / parser.options.size !== level) {
              if (count !== spaceLength) {
                result = helpers.addUnique(result, {
                  'ruleId': parser.rule.name,
                  'line': node.content[i + 1].start.line,
                  'column': node.content[i + 1].start.column,
                  'message': 'Mixed tabs and spaces',
                  'severity': parser.severity
                });
              }
              if (i !== node.length - 1) {
                result = helpers.addUnique(result, {
                  'ruleId': parser.rule.name,
                  'line': node.content[i + 1].start.line,
                  'column': node.content[i + 1].start.column,
                  'message': 'Indentation of ' + spaceLength + ', expected ' + level * parser.options.size,
                  'severity': parser.severity
                });
              }
            }
          }
        }

        if (n.is('block') || n.is('atrulers') || (n.is('parentheses') && !node.is('atruleb'))) {
          level++;
        }

        processNode(n, level);
      }
    };

    processNode(ast);

    return result;
  }
};
<|endoftext|>


<commit_before>// GFM table, non-standard

'use strict';

function getLine(state, line) {
  var pos = state.bMarks[line] + state.blkIndent,
      max = state.eMarks[line];

  return state.src.substr(pos, max - pos);
}

module.exports = function table(state, startLine, endLine, silent) {
  var ch, lineText, pos, i, nextLine, rows,
      aligns, t, tableLines, tbodyLines;

  // should have at least three lines
  if (startLine + 2 > endLine) { return false; }

  nextLine = startLine + 1;

  if (state.tShift[nextLine] < state.blkIndent) { return false; }

  // first character of the second line should be '|' or '-'

  pos = state.bMarks[nextLine] + state.tShift[nextLine];
  if (pos >= state.eMarks[nextLine]) { return false; }

  ch = state.src.charCodeAt(pos);
  if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */) { return false; }

  lineText = getLine(state, startLine + 1);
  if (!/^[-:| ]+$/.test(lineText)) { return false; }

  rows = lineText.split('|');
  if (rows <= 2) { return false; }
  aligns = [];
  for (i = 0; i < rows.length; i++) {
    t = rows[i].trim();
    if (!t) {
      // allow empty columns before and after table, but not in between columns;
      // e.g. allow ` |---| `, disallow ` ---||--- `
      if (i === 0 || i === rows.length - 1) {
        continue;
      } else {
        return false;
      }
    }

    if (!/^:?-+:?$/.test(t)) { return false; }
    if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
      aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
    } else if (t.charCodeAt(0) === 0x3A/* : */) {
      aligns.push('left');
    } else {
      aligns.push('');
    }
  }

  lineText = getLine(state, startLine).trim();
  if (lineText.indexOf('|') === -1) { return false; }
  rows = lineText.replace(/^\||\|$/g, '').split('|');
  if (aligns.length !== rows.length) { return false; }
  if (silent) { return true; }

  state.tokens.push({
    type: 'table_open',
    lines: tableLines = [ startLine, 0 ],
    level: state.level++
  });
  state.tokens.push({
    type: 'thead_open',
    lines: [ startLine, startLine + 1 ],
    level: state.level++
  });

  state.tokens.push({
    type: 'tr_open',
    lines: [ startLine, startLine + 1 ],
    level: state.level++
  });
  for (i = 0; i < rows.length; i++) {
    state.tokens.push({
      type: 'th_open',
      align: aligns[i],
      lines: [ startLine, startLine + 1 ],
      level: state.level++
    });
    state.tokens.push({
      type: 'inline',
      content: rows[i].trim(),
      lines: [ startLine, startLine + 1 ],
      level: state.level,
      children: []
    });
    state.tokens.push({ type: 'th_close', level: --state.level });
  }
  state.tokens.push({ type: 'tr_close', level: --state.level });
  state.tokens.push({ type: 'thead_close', level: --state.level });

  state.tokens.push({
    type: 'tbody_open',
    lines: tbodyLines = [ startLine + 2, 0 ],
    level: state.level++
  });

  for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
    if (state.tShift[nextLine] < state.blkIndent) { break; }

    lineText = getLine(state, nextLine).trim();
    if (lineText.indexOf('|') === -1) { break; }
    rows = lineText.replace(/^\||\|$/g, '').split('|');

    state.tokens.push({ type: 'tr_open', level: state.level++ });
    for (i = 0; i < rows.length; i++) {
      state.tokens.push({ type: 'td_open', align: aligns[i], level: state.level++ });
      state.tokens.push({
        type: 'inline',
        content: rows[i].replace(/^\|? *| *\|?$/g, ''),
        level: state.level,
        children: []
      });
      state.tokens.push({ type: 'td_close', level: --state.level });
    }
    state.tokens.push({ type: 'tr_close', level: --state.level });
  }
  state.tokens.push({ type: 'tbody_close', level: --state.level });
  state.tokens.push({ type: 'table_close', level: --state.level });

  tableLines[1] = tbodyLines[1] = nextLine;
  state.line = nextLine;
  return true;
};
<commit_msg>Fix comparing array and number<commit_after>// GFM table, non-standard

'use strict';

function getLine(state, line) {
  var pos = state.bMarks[line] + state.blkIndent,
      max = state.eMarks[line];

  return state.src.substr(pos, max - pos);
}

module.exports = function table(state, startLine, endLine, silent) {
  var ch, lineText, pos, i, nextLine, rows,
      aligns, t, tableLines, tbodyLines;

  // should have at least three lines
  if (startLine + 2 > endLine) { return false; }

  nextLine = startLine + 1;

  if (state.tShift[nextLine] < state.blkIndent) { return false; }

  // first character of the second line should be '|' or '-'

  pos = state.bMarks[nextLine] + state.tShift[nextLine];
  if (pos >= state.eMarks[nextLine]) { return false; }

  ch = state.src.charCodeAt(pos);
  if (ch !== 0x7C/* | */ && ch !== 0x2D/* - */ && ch !== 0x3A/* : */) { return false; }

  lineText = getLine(state, startLine + 1);
  if (!/^[-:| ]+$/.test(lineText)) { return false; }

  rows = lineText.split('|');
  if (rows.length < 2) { return false; }
  aligns = [];
  for (i = 0; i < rows.length; i++) {
    t = rows[i].trim();
    if (!t) {
      // allow empty columns before and after table, but not in between columns;
      // e.g. allow ` |---| `, disallow ` ---||--- `
      if (i === 0 || i === rows.length - 1) {
        continue;
      } else {
        return false;
      }
    }

    if (!/^:?-+:?$/.test(t)) { return false; }
    if (t.charCodeAt(t.length - 1) === 0x3A/* : */) {
      aligns.push(t.charCodeAt(0) === 0x3A/* : */ ? 'center' : 'right');
    } else if (t.charCodeAt(0) === 0x3A/* : */) {
      aligns.push('left');
    } else {
      aligns.push('');
    }
  }

  lineText = getLine(state, startLine).trim();
  if (lineText.indexOf('|') === -1) { return false; }
  rows = lineText.replace(/^\||\|$/g, '').split('|');
  if (aligns.length !== rows.length) { return false; }
  if (silent) { return true; }

  state.tokens.push({
    type: 'table_open',
    lines: tableLines = [ startLine, 0 ],
    level: state.level++
  });
  state.tokens.push({
    type: 'thead_open',
    lines: [ startLine, startLine + 1 ],
    level: state.level++
  });

  state.tokens.push({
    type: 'tr_open',
    lines: [ startLine, startLine + 1 ],
    level: state.level++
  });
  for (i = 0; i < rows.length; i++) {
    state.tokens.push({
      type: 'th_open',
      align: aligns[i],
      lines: [ startLine, startLine + 1 ],
      level: state.level++
    });
    state.tokens.push({
      type: 'inline',
      content: rows[i].trim(),
      lines: [ startLine, startLine + 1 ],
      level: state.level,
      children: []
    });
    state.tokens.push({ type: 'th_close', level: --state.level });
  }
  state.tokens.push({ type: 'tr_close', level: --state.level });
  state.tokens.push({ type: 'thead_close', level: --state.level });

  state.tokens.push({
    type: 'tbody_open',
    lines: tbodyLines = [ startLine + 2, 0 ],
    level: state.level++
  });

  for (nextLine = startLine + 2; nextLine < endLine; nextLine++) {
    if (state.tShift[nextLine] < state.blkIndent) { break; }

    lineText = getLine(state, nextLine).trim();
    if (lineText.indexOf('|') === -1) { break; }
    rows = lineText.replace(/^\||\|$/g, '').split('|');

    state.tokens.push({ type: 'tr_open', level: state.level++ });
    for (i = 0; i < rows.length; i++) {
      state.tokens.push({ type: 'td_open', align: aligns[i], level: state.level++ });
      state.tokens.push({
        type: 'inline',
        content: rows[i].replace(/^\|? *| *\|?$/g, ''),
        level: state.level,
        children: []
      });
      state.tokens.push({ type: 'td_close', level: --state.level });
    }
    state.tokens.push({ type: 'tr_close', level: --state.level });
  }
  state.tokens.push({ type: 'tbody_close', level: --state.level });
  state.tokens.push({ type: 'table_close', level: --state.level });

  tableLines[1] = tbodyLines[1] = nextLine;
  state.line = nextLine;
  return true;
};
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var path = require('path');
var rr = require('recursive-readdir');
var yaml = require('js-yaml');

var swagger2openapi = require('./index.js');
var validator = require('./validate.js');

var argv = require('yargs')
	.usage('testRunner [options] [{path-to-specs}]')
	.count('verbose')
	.alias('v','verbose')
	.describe('verbose','Increase verbosity')
	.help('h')
    .alias('h', 'help')
	.strict()
	.version(function() {
		return require('../package.json').version;
	})
	.argv;

var red = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[31m';
var green = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[32m';
var normal = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[0m';

var pass = 0;
var fail = 0;
var failures = [];

var pathspec = argv._.length>0 ? argv._[0] : '../openapi-directory/APIs/';

var options = argv;

function check(file,force) {
	var result = false;
	var components = file.split(path.sep);
	var name = components[components.length-1];

	if ((name.indexOf('.yaml')>=0) || (name.indexOf('.json')>=0) || force) {

		var srcStr = fs.readFileSync(path.resolve(file),'utf8');
		var src;
		try {
			if (name.indexOf('.yaml')>=0) {
				src = yaml.safeLoad(srcStr);
			}
			else {
				src = JSON.parse(srcStr);
			}
		}
		catch (ex) {}

		if (!src || ((!src.swagger && !src.openapi))) return true;
		console.log(normal+file);

		try {
	        result = swagger2openapi.convert(src, options);
			var resultStr = JSON.stringify(result);

			validator.validate(result,options);

			resultStr = yaml.safeDump(result); // should be representable safely in yaml
			resultStr.should.not.be.exactly('{}');

		  	console.log(green+'  %s %s',src.info.title,src.info.version);
			console.log('  %s',src.swagger ? src.host : (src.servers && src.servers.length ? src.servers[0].url : ''));
			result = true;
		}
		catch (ex) {
			console.log(ex.message);
			result = false;
		}
		if (result) {
			pass++;
		}
		else {
			fail++;
		}
	}
	else {
		result = true;
	}
	return result;
}

process.exitCode = 1;
pathspec = path.resolve(pathspec);
var stats = fs.statSync(pathspec);
if (stats.isFile()) {
	if (!check(pathspec,true)) {
		failures.push(pathspec);
	}
}
else {
	rr(pathspec, function (err, files) {
		for (var i in files) {
			if (!check(files[i])) {
				failures.push(files[i]);
			}
		}
	});
}

process.on('exit', function(code) {
	if (failures.length>0) {
		failures.sort();
		console.log(red);
		console.log('Failures:');
		for (var f in failures) {
			console.log(failures[f]);
		}
	}
	console.log(normal);
	console.log('Tests: %s passing, %s failing', pass, fail);
	process.exitCode = ((fail === 0) && (pass > 0)) ? 0 : 1;
});
<commit_msg>testRunner; cosmetic changes<commit_after>'use strict';

var fs = require('fs');
var path = require('path');
var rr = require('recursive-readdir');
var yaml = require('js-yaml');

var swagger2openapi = require('./index.js');
var validator = require('./validate.js');

var argv = require('yargs')
	.usage('testRunner [options] [{path-to-specs}]')
	.count('verbose')
	.alias('v','verbose')
	.describe('verbose','Increase verbosity')
	.help('h')
    .alias('h', 'help')
	.strict()
	.version(function() {
		return require('../package.json').version;
	})
	.argv;

var red = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[31m';
var green = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[32m';
var normal = process.env.NODE_DISABLE_COLORS ? '' : '\x1b[0m';

var pass = 0;
var fail = 0;
var failures = [];

var pathspec = argv._.length>0 ? argv._[0] : '../openapi-directory/APIs/';

var options = argv;

function check(file,force) {
	var result = false;
	var components = file.split(path.sep);
	var name = components[components.length-1];

	if ((name.indexOf('.yaml')>=0) || (name.indexOf('.json')>=0) || force) {

		var srcStr = fs.readFileSync(path.resolve(file),'utf8');
		var src;
		try {
			if (name.indexOf('.yaml')>=0) {
				src = yaml.safeLoad(srcStr);
			}
			else {
				src = JSON.parse(srcStr);
			}
		}
		catch (ex) {}

		if (!src || ((!src.swagger && !src.openapi))) return true;
		console.log(normal+file);

		try {
	        result = swagger2openapi.convert(src, options);
			var resultStr = JSON.stringify(result);

			validator.validate(result,options);

			resultStr = yaml.safeDump(result); // should be representable safely in yaml
			resultStr.should.not.be.exactly('{}');

		  	console.log(green+'  %s %s',src.info.title,src.info.version);
			console.log('  %s',src.swagger ? (src.host ? src.host : 'relative') : (src.servers && src.servers.length ? src.servers[0].url : 'relative'));
			result = true;
		}
		catch (ex) {
			console.log(red+ex.message);
			result = false;
		}
		if (result) {
			pass++;
		}
		else {
			fail++;
		}
	}
	else {
		result = true;
	}
	return result;
}

process.exitCode = 1;
pathspec = path.resolve(pathspec);
var stats = fs.statSync(pathspec);
if (stats.isFile()) {
	if (!check(pathspec,true)) {
		failures.push(pathspec);
	}
}
else {
	rr(pathspec, function (err, files) {
		for (var i in files) {
			if (!check(files[i])) {
				failures.push(files[i]);
			}
		}
	});
}

process.on('exit', function(code) {
	if (failures.length>0) {
		failures.sort();
		console.log(normal+'\nFailures:'+red);
		for (var f in failures) {
			console.log(failures[f]);
		}
	}
	console.log(normal);
	console.log('Tests: %s passing, %s failing', pass, fail);
	process.exitCode = ((fail === 0) && (pass > 0)) ? 0 : 1;
});
<|endoftext|>


<commit_before>'use strict';

var mean = require('meanio');

module.exports = function(System, app, auth, database) {

  // Home route
  var index = require('../controllers/index');
  app.route('/')
    .get(index.render);

  app.get('/*',function(req,res,next){
        res.header("workerID" , JSON.stringify(mean.options.workerid) );
        next(); // http://expressjs.com/guide.html#passing-route control
  });
};
<commit_msg>fixing string on header<commit_after>'use strict';

var mean = require('meanio');

module.exports = function(System, app, auth, database) {

  // Home route
  var index = require('../controllers/index');
  app.route('/')
    .get(index.render);

  app.get('/*',function(req,res,next){
        res.header('workerID' , JSON.stringify(mean.options.workerid) );
        next(); // http://expressjs.com/guide.html#passing-route control
  });
};
<|endoftext|>


<commit_before>export default function Bounds(b) {
  this.clear();
  if (b) this.union(b);
}

var prototype = Bounds.prototype;

prototype.clone = function() {
  return new Bounds(this);
};

prototype.clear = function() {
  this.x1 = +Number.MAX_VALUE;
  this.y1 = +Number.MAX_VALUE;
  this.x2 = -Number.MAX_VALUE;
  this.y2 = -Number.MAX_VALUE;
  return this;
};

prototype.empty = function() {
  return (
    this.x1 === +Number.MAX_VALUE &&
    this.y1 === +Number.MAX_VALUE &&
    this.x2 === -Number.MAX_VALUE &&
    this.y2 === -Number.MAX_VALUE
  );
};

prototype.set = function(x1, y1, x2, y2) {
  if (x2 < x1) {
    this.x2 = x1;
    this.x1 = x2;
  } else {
    this.x1 = x1;
    this.x2 = x2;
  }
  if (y2 < y1) {
    this.y2 = y1;
    this.y1 = y2;
  } else {
    this.y1 = y1;
    this.y2 = y2;
  }
  return this;
};

prototype.add = function(x, y) {
  if (x < this.x1) this.x1 = x;
  if (y < this.y1) this.y1 = y;
  if (x > this.x2) this.x2 = x;
  if (y > this.y2) this.y2 = y;
  return this;
};

prototype.expand = function(d) {
  this.x1 -= d;
  this.y1 -= d;
  this.x2 += d;
  this.y2 += d;
  return this;
};

prototype.round = function() {
  this.x1 = Math.floor(this.x1);
  this.y1 = Math.floor(this.y1);
  this.x2 = Math.ceil(this.x2);
  this.y2 = Math.ceil(this.y2);
  return this;
};

prototype.translate = function(dx, dy) {
  this.x1 += dx;
  this.x2 += dx;
  this.y1 += dy;
  this.y2 += dy;
  return this;
};

prototype.rotate = function(angle, x, y) {
  var cos = Math.cos(angle),
      sin = Math.sin(angle),
      cx = x - x*cos + y*sin,
      cy = y - x*sin - y*cos,
      x1 = this.x1, x2 = this.x2,
      y1 = this.y1, y2 = this.y2;

  return this.clear()
    .add(cos*x1 - sin*y1 + cx,  sin*x1 + cos*y1 + cy)
    .add(cos*x1 - sin*y2 + cx,  sin*x1 + cos*y2 + cy)
    .add(cos*x2 - sin*y1 + cx,  sin*x2 + cos*y1 + cy)
    .add(cos*x2 - sin*y2 + cx,  sin*x2 + cos*y2 + cy);
};

prototype.union = function(b) {
  if (b.x1 < this.x1) this.x1 = b.x1;
  if (b.y1 < this.y1) this.y1 = b.y1;
  if (b.x2 > this.x2) this.x2 = b.x2;
  if (b.y2 > this.y2) this.y2 = b.y2;
  return this;
};

prototype.intersect = function(b) {
  if (b.x1 > this.x1) this.x1 = b.x1;
  if (b.y1 > this.y1) this.y1 = b.y1;
  if (b.x2 < this.x2) this.x2 = b.x2;
  if (b.y2 < this.y2) this.y2 = b.y2;
  return this;
};

prototype.intersect = function(b) {
  if (b.x1 > this.x1) this.x1 = b.x1;
  if (b.y1 > this.y1) this.y1 = b.y1;
  if (b.x2 < this.x2) this.x2 = b.x2;
  if (b.y2 < this.y2) this.y2 = b.y2;
  return this;
};

prototype.encloses = function(b) {
  return b && (
    this.x1 <= b.x1 &&
    this.x2 >= b.x2 &&
    this.y1 <= b.y1 &&
    this.y2 >= b.y2
  );
};

prototype.alignsWith = function(b) {
  return b && (
    this.x1 == b.x1 ||
    this.x2 == b.x2 ||
    this.y1 == b.y1 ||
    this.y2 == b.y2
  );
};

prototype.intersects = function(b) {
  return b && !(
    this.x2 < b.x1 ||
    this.x1 > b.x2 ||
    this.y2 < b.y1 ||
    this.y1 > b.y2
  );
};

prototype.contains = function(x, y) {
  return !(
    x < this.x1 ||
    x > this.x2 ||
    y < this.y1 ||
    y > this.y2
  );
};

prototype.width = function() {
  return this.x2 - this.x1;
};

prototype.height = function() {
  return this.y2 - this.y1;
};
<commit_msg>Add Bounds rotatedPoints, remove duplicate code.<commit_after>export default function Bounds(b) {
  this.clear();
  if (b) this.union(b);
}

var prototype = Bounds.prototype;

prototype.clone = function() {
  return new Bounds(this);
};

prototype.clear = function() {
  this.x1 = +Number.MAX_VALUE;
  this.y1 = +Number.MAX_VALUE;
  this.x2 = -Number.MAX_VALUE;
  this.y2 = -Number.MAX_VALUE;
  return this;
};

prototype.empty = function() {
  return (
    this.x1 === +Number.MAX_VALUE &&
    this.y1 === +Number.MAX_VALUE &&
    this.x2 === -Number.MAX_VALUE &&
    this.y2 === -Number.MAX_VALUE
  );
};

prototype.set = function(x1, y1, x2, y2) {
  if (x2 < x1) {
    this.x2 = x1;
    this.x1 = x2;
  } else {
    this.x1 = x1;
    this.x2 = x2;
  }
  if (y2 < y1) {
    this.y2 = y1;
    this.y1 = y2;
  } else {
    this.y1 = y1;
    this.y2 = y2;
  }
  return this;
};

prototype.add = function(x, y) {
  if (x < this.x1) this.x1 = x;
  if (y < this.y1) this.y1 = y;
  if (x > this.x2) this.x2 = x;
  if (y > this.y2) this.y2 = y;
  return this;
};

prototype.expand = function(d) {
  this.x1 -= d;
  this.y1 -= d;
  this.x2 += d;
  this.y2 += d;
  return this;
};

prototype.round = function() {
  this.x1 = Math.floor(this.x1);
  this.y1 = Math.floor(this.y1);
  this.x2 = Math.ceil(this.x2);
  this.y2 = Math.ceil(this.y2);
  return this;
};

prototype.translate = function(dx, dy) {
  this.x1 += dx;
  this.x2 += dx;
  this.y1 += dy;
  this.y2 += dy;
  return this;
};

prototype.rotate = function(angle, x, y) {
  const p = this.rotatedPoints(angle, x, y);
  return this.clear()
    .add(p[0], p[1])
    .add(p[2], p[3])
    .add(p[4], p[5])
    .add(p[6], p[7]);
};

prototype.rotatedPoints = function(angle, x, y) {
  var {x1, y1, x2, y2} = this,
      cos = Math.cos(angle),
      sin = Math.sin(angle),
      cx = x - x*cos + y*sin,
      cy = y - x*sin - y*cos;

  return [
    cos*x1 - sin*y1 + cx, sin*x1 + cos*y1 + cy,
    cos*x1 - sin*y2 + cx, sin*x1 + cos*y2 + cy,
    cos*x2 - sin*y1 + cx, sin*x2 + cos*y1 + cy,
    cos*x2 - sin*y2 + cx, sin*x2 + cos*y2 + cy
  ];
};

prototype.union = function(b) {
  if (b.x1 < this.x1) this.x1 = b.x1;
  if (b.y1 < this.y1) this.y1 = b.y1;
  if (b.x2 > this.x2) this.x2 = b.x2;
  if (b.y2 > this.y2) this.y2 = b.y2;
  return this;
};

prototype.intersect = function(b) {
  if (b.x1 > this.x1) this.x1 = b.x1;
  if (b.y1 > this.y1) this.y1 = b.y1;
  if (b.x2 < this.x2) this.x2 = b.x2;
  if (b.y2 < this.y2) this.y2 = b.y2;
  return this;
};

prototype.encloses = function(b) {
  return b && (
    this.x1 <= b.x1 &&
    this.x2 >= b.x2 &&
    this.y1 <= b.y1 &&
    this.y2 >= b.y2
  );
};

prototype.alignsWith = function(b) {
  return b && (
    this.x1 == b.x1 ||
    this.x2 == b.x2 ||
    this.y1 == b.y1 ||
    this.y2 == b.y2
  );
};

prototype.intersects = function(b) {
  return b && !(
    this.x2 < b.x1 ||
    this.x1 > b.x2 ||
    this.y2 < b.y1 ||
    this.y1 > b.y2
  );
};

prototype.contains = function(x, y) {
  return !(
    x < this.x1 ||
    x > this.x2 ||
    y < this.y1 ||
    y > this.y2
  );
};

prototype.width = function() {
  return this.x2 - this.x1;
};

prototype.height = function() {
  return this.y2 - this.y1;
};
<|endoftext|>


<commit_before>'use strict';

/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/

/**
 * Data type map.
 *
 * Mapping of type ids to data types. The type id is specified by the high
 *
 * For reference, see rippled's definition:
 * https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol
 *                                                              /SField.cpp
 */

exports.types = [
  undefined,

  // Common
  'Int16',    // 1
  'Int32',    // 2
  'Int64',    // 3
  'Hash128',  // 4
  'Hash256',  // 5
  'Amount',   // 6
  'VL',       // 7
  'Account',  // 8

  // 9-13 reserved
  undefined,    // 9
  undefined,    // 10
  undefined,    // 11
  undefined,    // 12
  undefined,    // 13

  'Object',   // 14
  'Array',    // 15

  // Uncommon
  'Int8',     // 16
  'Hash160',  // 17
  'PathSet',  // 18
  'Vector256' // 19
];

/**
 * Field type map.
 *
 * Mapping of field type id to field type name.
 */

const FIELDS_MAP = exports.fields = {
  // Common types
  1: { // Int16
    1: 'LedgerEntryType',
    2: 'TransactionType'
  },
  2: { // Int32
    2: 'Flags',
    3: 'SourceTag',
    4: 'Sequence',
    5: 'PreviousTxnLgrSeq',
    6: 'LedgerSequence',
    7: 'CloseTime',
    8: 'ParentCloseTime',
    9: 'SigningTime',
    10: 'Expiration',
    11: 'TransferRate',
    12: 'WalletSize',
    13: 'OwnerCount',
    14: 'DestinationTag',
    // Skip 15
    16: 'HighQualityIn',
    17: 'HighQualityOut',
    18: 'LowQualityIn',
    19: 'LowQualityOut',
    20: 'QualityIn',
    21: 'QualityOut',
    22: 'StampEscrow',
    23: 'BondAmount',
    24: 'LoadFee',
    25: 'OfferSequence',
    26: 'FirstLedgerSequence',
    27: 'LastLedgerSequence',
    28: 'TransactionIndex',
    29: 'OperationLimit',
    30: 'ReferenceFeeUnits',
    31: 'ReserveBase',
    32: 'ReserveIncrement',
    33: 'SetFlag',
    34: 'ClearFlag'
  },
  3: { // Int64
    1: 'IndexNext',
    2: 'IndexPrevious',
    3: 'BookNode',
    4: 'OwnerNode',
    5: 'BaseFee',
    6: 'ExchangeRate',
    7: 'LowNode',
    8: 'HighNode'
  },
  4: { // Hash128
    1: 'EmailHash'
  },
  5: { // Hash256
    1: 'LedgerHash',
    2: 'ParentHash',
    3: 'TransactionHash',
    4: 'AccountHash',
    5: 'PreviousTxnID',
    6: 'LedgerIndex',
    7: 'WalletLocator',
    8: 'RootIndex',
    9: 'AccountTxnID',
    16: 'BookDirectory',
    17: 'InvoiceID',
    18: 'Nickname',
    19: 'Amendment',
    20: 'TicketID'
  },
  6: { // Amount
    1: 'Amount',
    2: 'Balance',
    3: 'LimitAmount',
    4: 'TakerPays',
    5: 'TakerGets',
    6: 'LowLimit',
    7: 'HighLimit',
    8: 'Fee',
    9: 'SendMax',
    16: 'MinimumOffer',
    17: 'RippleEscrow',
    18: 'DeliveredAmount'
  },
  7: { // VL
    1: 'PublicKey',
    2: 'MessageKey',
    3: 'SigningPubKey',
    4: 'TxnSignature',
    5: 'Generator',
    6: 'Signature',
    7: 'Domain',
    8: 'FundCode',
    9: 'RemoveCode',
    10: 'ExpireCode',
    11: 'CreateCode',
    12: 'MemoType',
    13: 'MemoData',
    14: 'MemoFormat'
  },
  8: { // Account
    1: 'Account',
    2: 'Owner',
    3: 'Destination',
    4: 'Issuer',
    7: 'Target',
    8: 'RegularKey'
  },
  14: { // Object
    1: undefined,  // end of Object
    2: 'TransactionMetaData',
    3: 'CreatedNode',
    4: 'DeletedNode',
    5: 'ModifiedNode',
    6: 'PreviousFields',
    7: 'FinalFields',
    8: 'NewFields',
    9: 'TemplateEntry',
    10: 'Memo'
  },
  15: { // Array
    1: undefined,  // end of Array
    2: 'SigningAccounts',
    3: 'TxnSignatures',
    4: 'Signatures',
    5: 'Template',
    6: 'Necessary',
    7: 'Sufficient',
    8: 'AffectedNodes',
    9: 'Memos'
  },

  // Uncommon types
  16: { // Int8
    1: 'CloseResolution',
    2: 'TemplateEntryType',
    3: 'TransactionResult'
  },
  17: { // Hash160
    1: 'TakerPaysCurrency',
    2: 'TakerPaysIssuer',
    3: 'TakerGetsCurrency',
    4: 'TakerGetsIssuer'
  },
  18: { // PathSet
    1: 'Paths'
  },
  19: { // Vector256
    1: 'Indexes',
    2: 'Hashes',
    3: 'Amendments'
  }
};

let INVERSE_FIELDS_MAP = exports.fieldsInverseMap = { };

Object.keys(FIELDS_MAP).forEach(function(k1) {
  Object.keys(FIELDS_MAP[k1]).forEach(function(k2) {
    INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [ Number(k1), Number(k2) ];
  });
});

const REQUIRED = exports.REQUIRED = 0,
      OPTIONAL = exports.OPTIONAL = 1,
      DEFAULT  = exports.DEFAULT  = 2;

const base = [
  [ 'TransactionType'    , REQUIRED ],
  [ 'Flags'              , OPTIONAL ],
  [ 'SourceTag'          , OPTIONAL ],
  [ 'LastLedgerSequence' , OPTIONAL ],
  [ 'Account'            , REQUIRED ],
  [ 'Sequence'           , REQUIRED ],
  [ 'Fee'                , REQUIRED ],
  [ 'OperationLimit'     , OPTIONAL ],
  [ 'SigningPubKey'      , REQUIRED ],
  [ 'TxnSignature'       , OPTIONAL ],
  [ 'AccountTxnID'       , OPTIONAL ],
  [ 'Memos'              , OPTIONAL ]
];

exports.tx = {
  AccountSet: [3].concat(base, [
    [ 'EmailHash'          , OPTIONAL ],
    [ 'WalletLocator'      , OPTIONAL ],
    [ 'WalletSize'         , OPTIONAL ],
    [ 'MessageKey'         , OPTIONAL ],
    [ 'Domain'             , OPTIONAL ],
    [ 'TransferRate'       , OPTIONAL ],
    [ 'SetFlag'            , OPTIONAL ],
    [ 'ClearFlag'          , OPTIONAL ]
  ]),
  TrustSet: [20].concat(base, [
    [ 'LimitAmount'        , OPTIONAL ],
    [ 'QualityIn'          , OPTIONAL ],
    [ 'QualityOut'         , OPTIONAL ]
  ]),
  OfferCreate: [7].concat(base, [
    [ 'TakerPays'          , REQUIRED ],
    [ 'TakerGets'          , REQUIRED ],
    [ 'Expiration'         , OPTIONAL ],
    [ 'OfferSequence'      , OPTIONAL ]
  ]),
  OfferCancel: [8].concat(base, [
    [ 'OfferSequence'      , REQUIRED ]
  ]),
  SetRegularKey: [5].concat(base, [
    [ 'RegularKey'         , OPTIONAL ]
  ]),
  Payment: [0].concat(base, [
    [ 'Destination'        , REQUIRED ],
    [ 'Amount'             , REQUIRED ],
    [ 'SendMax'            , OPTIONAL ],
    [ 'Paths'              , DEFAULT  ],
    [ 'InvoiceID'          , OPTIONAL ],
    [ 'DestinationTag'     , OPTIONAL ]
  ]),
  Contract: [9].concat(base, [
    [ 'Expiration'         , REQUIRED ],
    [ 'BondAmount'         , REQUIRED ],
    [ 'StampEscrow'        , REQUIRED ],
    [ 'RippleEscrow'       , REQUIRED ],
    [ 'CreateCode'         , OPTIONAL ],
    [ 'FundCode'           , OPTIONAL ],
    [ 'RemoveCode'         , OPTIONAL ],
    [ 'ExpireCode'         , OPTIONAL ]
  ]),
  RemoveContract: [10].concat(base, [
    [ 'Target'             , REQUIRED ]
  ]),
  EnableFeature: [100].concat(base, [
    [ 'Feature'            , REQUIRED ]
  ]),
  EnableAmendment: [100].concat(base, [
    [ 'Amendment'          , REQUIRED ]
  ]),
  SetFee: [101].concat(base, [
    [ 'BaseFee'            , REQUIRED ],
    [ 'ReferenceFeeUnits'  , REQUIRED ],
    [ 'ReserveBase'        , REQUIRED ],
    [ 'ReserveIncrement'   , REQUIRED ]
  ]),
  TicketCreate: [10].concat(base, [
    [ 'Target'             , OPTIONAL ],
    [ 'Expiration'         , OPTIONAL ]
  ]),
  TicketCancel: [11].concat(base, [
    [ 'TicketID'           , REQUIRED ]
  ])
};

const sleBase = [
  ['LedgerIndex',          OPTIONAL],
  ['LedgerEntryType',      REQUIRED],
  ['Flags',                REQUIRED]
];

exports.ledger = {
  AccountRoot: [97].concat(sleBase,[
    ['Sequence',           REQUIRED],
    ['PreviousTxnLgrSeq',  REQUIRED],
    ['TransferRate',       OPTIONAL],
    ['WalletSize',         OPTIONAL],
    ['OwnerCount',         REQUIRED],
    ['EmailHash',          OPTIONAL],
    ['PreviousTxnID',      REQUIRED],
    ['AccountTxnID',       OPTIONAL],
    ['WalletLocator',      OPTIONAL],
    ['Balance',            REQUIRED],
    ['MessageKey',         OPTIONAL],
    ['Domain',             OPTIONAL],
    ['Account',            REQUIRED],
    ['RegularKey',         OPTIONAL]]),
  Contract: [99].concat(sleBase,[
    ['PreviousTxnLgrSeq',  REQUIRED],
    ['Expiration',         REQUIRED],
    ['BondAmount',         REQUIRED],
    ['PreviousTxnID',      REQUIRED],
    ['Balance',            REQUIRED],
    ['FundCode',           OPTIONAL],
    ['RemoveCode',         OPTIONAL],
    ['ExpireCode',         OPTIONAL],
    ['CreateCode',         OPTIONAL],
    ['Account',            REQUIRED],
    ['Owner',              REQUIRED],
    ['Issuer',             REQUIRED]]),
  DirectoryNode: [100].concat(sleBase,[
    ['IndexNext',          OPTIONAL],
    ['IndexPrevious',      OPTIONAL],
    ['ExchangeRate',       OPTIONAL],
    ['RootIndex',          REQUIRED],
    ['Owner',              OPTIONAL],
    ['TakerPaysCurrency',  OPTIONAL],
    ['TakerPaysIssuer',    OPTIONAL],
    ['TakerGetsCurrency',  OPTIONAL],
    ['TakerGetsIssuer',    OPTIONAL],
    ['Indexes',            REQUIRED]]),
  EnabledFeatures: [102].concat(sleBase,[
    ['Features',           REQUIRED]]),
  FeeSettings: [115].concat(sleBase,[
    ['ReferenceFeeUnits',  REQUIRED],
    ['ReserveBase',        REQUIRED],
    ['ReserveIncrement',   REQUIRED],
    ['BaseFee',            REQUIRED],
    ['LedgerIndex',        OPTIONAL]]),
  GeneratorMap: [103].concat(sleBase,[
    ['Generator',          REQUIRED]]),
  LedgerHashes: [104].concat(sleBase,[
    ['LedgerEntryType',      REQUIRED],
    ['Flags',                REQUIRED],
    ['FirstLedgerSequence',  OPTIONAL],
    ['LastLedgerSequence',   OPTIONAL],
    ['LedgerIndex',          OPTIONAL],
    ['Hashes',               REQUIRED]]),
  Nickname: [110].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['MinimumOffer',        OPTIONAL],
    ['Account',             REQUIRED]]),
  Offer: [111].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['Sequence',            REQUIRED],
    ['PreviousTxnLgrSeq',   REQUIRED],
    ['Expiration',          OPTIONAL],
    ['BookNode',            REQUIRED],
    ['OwnerNode',           REQUIRED],
    ['PreviousTxnID',       REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['BookDirectory',       REQUIRED],
    ['TakerPays',           REQUIRED],
    ['TakerGets',           REQUIRED],
    ['Account',             REQUIRED]]),
  RippleState: [114].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['PreviousTxnLgrSeq',   REQUIRED],
    ['HighQualityIn',       OPTIONAL],
    ['HighQualityOut',      OPTIONAL],
    ['LowQualityIn',        OPTIONAL],
    ['LowQualityOut',       OPTIONAL],
    ['LowNode',             OPTIONAL],
    ['HighNode',            OPTIONAL],
    ['PreviousTxnID',       REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['Balance',             REQUIRED],
    ['LowLimit',            REQUIRED],
    ['HighLimit',           REQUIRED]])
};

exports.metadata = [
  [ 'TransactionIndex'     , REQUIRED ],
  [ 'TransactionResult'    , REQUIRED ],
  [ 'AffectedNodes'        , REQUIRED ]
];

exports.ter = {
  tesSUCCESS               : 0,
  tecCLAIM                 : 100,
  tecPATH_PARTIAL          : 101,
  tecUNFUNDED_ADD          : 102,
  tecUNFUNDED_OFFER        : 103,
  tecUNFUNDED_PAYMENT      : 104,
  tecFAILED_PROCESSING     : 105,
  tecDIR_FULL              : 121,
  tecINSUF_RESERVE_LINE    : 122,
  tecINSUF_RESERVE_OFFER   : 123,
  tecNO_DST                : 124,
  tecNO_DST_INSUF_XRP      : 125,
  tecNO_LINE_INSUF_RESERVE : 126,
  tecNO_LINE_REDUNDANT     : 127,
  tecPATH_DRY              : 128,
  tecUNFUNDED              : 129,  // Deprecated, old ambiguous unfunded.
  tecMASTER_DISABLED       : 130,
  tecNO_REGULAR_KEY        : 131,
  tecOWNERS                : 132,
  tecNO_ISSUER             : 133,
  tecNO_AUTH               : 134,
  tecNO_LINE               : 135,
  tecINSUFF_FEE            : 136,
  tecFROZEN                : 137,
  tecNO_TARGET             : 138,
  tecNO_PERMISSION         : 139,
  tecNO_ENTRY              : 140,
  tecINSUFFICIENT_RESERVE  : 141,
  tecNEED_MASTER_KEY       : 142,
  tecDST_TAG_NEEDED        : 143,
  tecINTERNAL              : 144
};
<commit_msg>add 'DeliveredAmount' as optional metadata field<commit_after>'use strict';

/*eslint no-multi-spaces:0,space-in-brackets:0,key-spacing:0,comma-spacing:0*/

/**
 * Data type map.
 *
 * Mapping of type ids to data types. The type id is specified by the high
 *
 * For reference, see rippled's definition:
 * https://github.com/ripple/rippled/blob/develop/src/ripple/data/protocol
 *                                                              /SField.cpp
 */

exports.types = [
  undefined,

  // Common
  'Int16',    // 1
  'Int32',    // 2
  'Int64',    // 3
  'Hash128',  // 4
  'Hash256',  // 5
  'Amount',   // 6
  'VL',       // 7
  'Account',  // 8

  // 9-13 reserved
  undefined,    // 9
  undefined,    // 10
  undefined,    // 11
  undefined,    // 12
  undefined,    // 13

  'Object',   // 14
  'Array',    // 15

  // Uncommon
  'Int8',     // 16
  'Hash160',  // 17
  'PathSet',  // 18
  'Vector256' // 19
];

/**
 * Field type map.
 *
 * Mapping of field type id to field type name.
 */

const FIELDS_MAP = exports.fields = {
  // Common types
  1: { // Int16
    1: 'LedgerEntryType',
    2: 'TransactionType'
  },
  2: { // Int32
    2: 'Flags',
    3: 'SourceTag',
    4: 'Sequence',
    5: 'PreviousTxnLgrSeq',
    6: 'LedgerSequence',
    7: 'CloseTime',
    8: 'ParentCloseTime',
    9: 'SigningTime',
    10: 'Expiration',
    11: 'TransferRate',
    12: 'WalletSize',
    13: 'OwnerCount',
    14: 'DestinationTag',
    // Skip 15
    16: 'HighQualityIn',
    17: 'HighQualityOut',
    18: 'LowQualityIn',
    19: 'LowQualityOut',
    20: 'QualityIn',
    21: 'QualityOut',
    22: 'StampEscrow',
    23: 'BondAmount',
    24: 'LoadFee',
    25: 'OfferSequence',
    26: 'FirstLedgerSequence',
    27: 'LastLedgerSequence',
    28: 'TransactionIndex',
    29: 'OperationLimit',
    30: 'ReferenceFeeUnits',
    31: 'ReserveBase',
    32: 'ReserveIncrement',
    33: 'SetFlag',
    34: 'ClearFlag'
  },
  3: { // Int64
    1: 'IndexNext',
    2: 'IndexPrevious',
    3: 'BookNode',
    4: 'OwnerNode',
    5: 'BaseFee',
    6: 'ExchangeRate',
    7: 'LowNode',
    8: 'HighNode'
  },
  4: { // Hash128
    1: 'EmailHash'
  },
  5: { // Hash256
    1: 'LedgerHash',
    2: 'ParentHash',
    3: 'TransactionHash',
    4: 'AccountHash',
    5: 'PreviousTxnID',
    6: 'LedgerIndex',
    7: 'WalletLocator',
    8: 'RootIndex',
    9: 'AccountTxnID',
    16: 'BookDirectory',
    17: 'InvoiceID',
    18: 'Nickname',
    19: 'Amendment',
    20: 'TicketID'
  },
  6: { // Amount
    1: 'Amount',
    2: 'Balance',
    3: 'LimitAmount',
    4: 'TakerPays',
    5: 'TakerGets',
    6: 'LowLimit',
    7: 'HighLimit',
    8: 'Fee',
    9: 'SendMax',
    16: 'MinimumOffer',
    17: 'RippleEscrow',
    18: 'DeliveredAmount'
  },
  7: { // VL
    1: 'PublicKey',
    2: 'MessageKey',
    3: 'SigningPubKey',
    4: 'TxnSignature',
    5: 'Generator',
    6: 'Signature',
    7: 'Domain',
    8: 'FundCode',
    9: 'RemoveCode',
    10: 'ExpireCode',
    11: 'CreateCode',
    12: 'MemoType',
    13: 'MemoData',
    14: 'MemoFormat'
  },
  8: { // Account
    1: 'Account',
    2: 'Owner',
    3: 'Destination',
    4: 'Issuer',
    7: 'Target',
    8: 'RegularKey'
  },
  14: { // Object
    1: undefined,  // end of Object
    2: 'TransactionMetaData',
    3: 'CreatedNode',
    4: 'DeletedNode',
    5: 'ModifiedNode',
    6: 'PreviousFields',
    7: 'FinalFields',
    8: 'NewFields',
    9: 'TemplateEntry',
    10: 'Memo'
  },
  15: { // Array
    1: undefined,  // end of Array
    2: 'SigningAccounts',
    3: 'TxnSignatures',
    4: 'Signatures',
    5: 'Template',
    6: 'Necessary',
    7: 'Sufficient',
    8: 'AffectedNodes',
    9: 'Memos'
  },

  // Uncommon types
  16: { // Int8
    1: 'CloseResolution',
    2: 'TemplateEntryType',
    3: 'TransactionResult'
  },
  17: { // Hash160
    1: 'TakerPaysCurrency',
    2: 'TakerPaysIssuer',
    3: 'TakerGetsCurrency',
    4: 'TakerGetsIssuer'
  },
  18: { // PathSet
    1: 'Paths'
  },
  19: { // Vector256
    1: 'Indexes',
    2: 'Hashes',
    3: 'Amendments'
  }
};

let INVERSE_FIELDS_MAP = exports.fieldsInverseMap = { };

Object.keys(FIELDS_MAP).forEach(function(k1) {
  Object.keys(FIELDS_MAP[k1]).forEach(function(k2) {
    INVERSE_FIELDS_MAP[FIELDS_MAP[k1][k2]] = [ Number(k1), Number(k2) ];
  });
});

const REQUIRED = exports.REQUIRED = 0,
      OPTIONAL = exports.OPTIONAL = 1,
      DEFAULT  = exports.DEFAULT  = 2;

const base = [
  [ 'TransactionType'    , REQUIRED ],
  [ 'Flags'              , OPTIONAL ],
  [ 'SourceTag'          , OPTIONAL ],
  [ 'LastLedgerSequence' , OPTIONAL ],
  [ 'Account'            , REQUIRED ],
  [ 'Sequence'           , REQUIRED ],
  [ 'Fee'                , REQUIRED ],
  [ 'OperationLimit'     , OPTIONAL ],
  [ 'SigningPubKey'      , REQUIRED ],
  [ 'TxnSignature'       , OPTIONAL ],
  [ 'AccountTxnID'       , OPTIONAL ],
  [ 'Memos'              , OPTIONAL ]
];

exports.tx = {
  AccountSet: [3].concat(base, [
    [ 'EmailHash'          , OPTIONAL ],
    [ 'WalletLocator'      , OPTIONAL ],
    [ 'WalletSize'         , OPTIONAL ],
    [ 'MessageKey'         , OPTIONAL ],
    [ 'Domain'             , OPTIONAL ],
    [ 'TransferRate'       , OPTIONAL ],
    [ 'SetFlag'            , OPTIONAL ],
    [ 'ClearFlag'          , OPTIONAL ]
  ]),
  TrustSet: [20].concat(base, [
    [ 'LimitAmount'        , OPTIONAL ],
    [ 'QualityIn'          , OPTIONAL ],
    [ 'QualityOut'         , OPTIONAL ]
  ]),
  OfferCreate: [7].concat(base, [
    [ 'TakerPays'          , REQUIRED ],
    [ 'TakerGets'          , REQUIRED ],
    [ 'Expiration'         , OPTIONAL ],
    [ 'OfferSequence'      , OPTIONAL ]
  ]),
  OfferCancel: [8].concat(base, [
    [ 'OfferSequence'      , REQUIRED ]
  ]),
  SetRegularKey: [5].concat(base, [
    [ 'RegularKey'         , OPTIONAL ]
  ]),
  Payment: [0].concat(base, [
    [ 'Destination'        , REQUIRED ],
    [ 'Amount'             , REQUIRED ],
    [ 'SendMax'            , OPTIONAL ],
    [ 'Paths'              , DEFAULT  ],
    [ 'InvoiceID'          , OPTIONAL ],
    [ 'DestinationTag'     , OPTIONAL ]
  ]),
  Contract: [9].concat(base, [
    [ 'Expiration'         , REQUIRED ],
    [ 'BondAmount'         , REQUIRED ],
    [ 'StampEscrow'        , REQUIRED ],
    [ 'RippleEscrow'       , REQUIRED ],
    [ 'CreateCode'         , OPTIONAL ],
    [ 'FundCode'           , OPTIONAL ],
    [ 'RemoveCode'         , OPTIONAL ],
    [ 'ExpireCode'         , OPTIONAL ]
  ]),
  RemoveContract: [10].concat(base, [
    [ 'Target'             , REQUIRED ]
  ]),
  EnableFeature: [100].concat(base, [
    [ 'Feature'            , REQUIRED ]
  ]),
  EnableAmendment: [100].concat(base, [
    [ 'Amendment'          , REQUIRED ]
  ]),
  SetFee: [101].concat(base, [
    [ 'BaseFee'            , REQUIRED ],
    [ 'ReferenceFeeUnits'  , REQUIRED ],
    [ 'ReserveBase'        , REQUIRED ],
    [ 'ReserveIncrement'   , REQUIRED ]
  ]),
  TicketCreate: [10].concat(base, [
    [ 'Target'             , OPTIONAL ],
    [ 'Expiration'         , OPTIONAL ]
  ]),
  TicketCancel: [11].concat(base, [
    [ 'TicketID'           , REQUIRED ]
  ])
};

const sleBase = [
  ['LedgerIndex',          OPTIONAL],
  ['LedgerEntryType',      REQUIRED],
  ['Flags',                REQUIRED]
];

exports.ledger = {
  AccountRoot: [97].concat(sleBase,[
    ['Sequence',           REQUIRED],
    ['PreviousTxnLgrSeq',  REQUIRED],
    ['TransferRate',       OPTIONAL],
    ['WalletSize',         OPTIONAL],
    ['OwnerCount',         REQUIRED],
    ['EmailHash',          OPTIONAL],
    ['PreviousTxnID',      REQUIRED],
    ['AccountTxnID',       OPTIONAL],
    ['WalletLocator',      OPTIONAL],
    ['Balance',            REQUIRED],
    ['MessageKey',         OPTIONAL],
    ['Domain',             OPTIONAL],
    ['Account',            REQUIRED],
    ['RegularKey',         OPTIONAL]]),
  Contract: [99].concat(sleBase,[
    ['PreviousTxnLgrSeq',  REQUIRED],
    ['Expiration',         REQUIRED],
    ['BondAmount',         REQUIRED],
    ['PreviousTxnID',      REQUIRED],
    ['Balance',            REQUIRED],
    ['FundCode',           OPTIONAL],
    ['RemoveCode',         OPTIONAL],
    ['ExpireCode',         OPTIONAL],
    ['CreateCode',         OPTIONAL],
    ['Account',            REQUIRED],
    ['Owner',              REQUIRED],
    ['Issuer',             REQUIRED]]),
  DirectoryNode: [100].concat(sleBase,[
    ['IndexNext',          OPTIONAL],
    ['IndexPrevious',      OPTIONAL],
    ['ExchangeRate',       OPTIONAL],
    ['RootIndex',          REQUIRED],
    ['Owner',              OPTIONAL],
    ['TakerPaysCurrency',  OPTIONAL],
    ['TakerPaysIssuer',    OPTIONAL],
    ['TakerGetsCurrency',  OPTIONAL],
    ['TakerGetsIssuer',    OPTIONAL],
    ['Indexes',            REQUIRED]]),
  EnabledFeatures: [102].concat(sleBase,[
    ['Features',           REQUIRED]]),
  FeeSettings: [115].concat(sleBase,[
    ['ReferenceFeeUnits',  REQUIRED],
    ['ReserveBase',        REQUIRED],
    ['ReserveIncrement',   REQUIRED],
    ['BaseFee',            REQUIRED],
    ['LedgerIndex',        OPTIONAL]]),
  GeneratorMap: [103].concat(sleBase,[
    ['Generator',          REQUIRED]]),
  LedgerHashes: [104].concat(sleBase,[
    ['LedgerEntryType',      REQUIRED],
    ['Flags',                REQUIRED],
    ['FirstLedgerSequence',  OPTIONAL],
    ['LastLedgerSequence',   OPTIONAL],
    ['LedgerIndex',          OPTIONAL],
    ['Hashes',               REQUIRED]]),
  Nickname: [110].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['MinimumOffer',        OPTIONAL],
    ['Account',             REQUIRED]]),
  Offer: [111].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['Sequence',            REQUIRED],
    ['PreviousTxnLgrSeq',   REQUIRED],
    ['Expiration',          OPTIONAL],
    ['BookNode',            REQUIRED],
    ['OwnerNode',           REQUIRED],
    ['PreviousTxnID',       REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['BookDirectory',       REQUIRED],
    ['TakerPays',           REQUIRED],
    ['TakerGets',           REQUIRED],
    ['Account',             REQUIRED]]),
  RippleState: [114].concat(sleBase,[
    ['LedgerEntryType',     REQUIRED],
    ['Flags',               REQUIRED],
    ['PreviousTxnLgrSeq',   REQUIRED],
    ['HighQualityIn',       OPTIONAL],
    ['HighQualityOut',      OPTIONAL],
    ['LowQualityIn',        OPTIONAL],
    ['LowQualityOut',       OPTIONAL],
    ['LowNode',             OPTIONAL],
    ['HighNode',            OPTIONAL],
    ['PreviousTxnID',       REQUIRED],
    ['LedgerIndex',         OPTIONAL],
    ['Balance',             REQUIRED],
    ['LowLimit',            REQUIRED],
    ['HighLimit',           REQUIRED]])
};

exports.metadata = [
  [ 'DeliveredAmount'      , OPTIONAL ],
  [ 'TransactionIndex'     , REQUIRED ],
  [ 'TransactionResult'    , REQUIRED ],
  [ 'AffectedNodes'        , REQUIRED ]
];

exports.ter = {
  tesSUCCESS               : 0,
  tecCLAIM                 : 100,
  tecPATH_PARTIAL          : 101,
  tecUNFUNDED_ADD          : 102,
  tecUNFUNDED_OFFER        : 103,
  tecUNFUNDED_PAYMENT      : 104,
  tecFAILED_PROCESSING     : 105,
  tecDIR_FULL              : 121,
  tecINSUF_RESERVE_LINE    : 122,
  tecINSUF_RESERVE_OFFER   : 123,
  tecNO_DST                : 124,
  tecNO_DST_INSUF_XRP      : 125,
  tecNO_LINE_INSUF_RESERVE : 126,
  tecNO_LINE_REDUNDANT     : 127,
  tecPATH_DRY              : 128,
  tecUNFUNDED              : 129,  // Deprecated, old ambiguous unfunded.
  tecMASTER_DISABLED       : 130,
  tecNO_REGULAR_KEY        : 131,
  tecOWNERS                : 132,
  tecNO_ISSUER             : 133,
  tecNO_AUTH               : 134,
  tecNO_LINE               : 135,
  tecINSUFF_FEE            : 136,
  tecFROZEN                : 137,
  tecNO_TARGET             : 138,
  tecNO_PERMISSION         : 139,
  tecNO_ENTRY              : 140,
  tecINSUFFICIENT_RESERVE  : 141,
  tecNEED_MASTER_KEY       : 142,
  tecDST_TAG_NEEDED        : 143,
  tecINTERNAL              : 144
};
<|endoftext|>


<commit_before>var styleParser = require('style-attr');
var utils = require('../utils/');

/**
 * Component class definition.
 *
 * Components configure appearance, modify behavior, or add functionality to
 * entities. The behavior and appearance of an entity can be changed at runtime
 * by adding, removing, or updating components. Entities do not share instances
 * of components.
 *
 * @namespace Component
 * @property {object} data - Stores component data, populated by parsing the
 *           attribute name of the component plus applying defaults and mixins.
 * @property {object} el - Reference to the entity element.
 * @property {string} name - Name of the attribute the component is connected
 *           to.
 * @member {Element} el
 * @member {object} data
 * @member {function} getData
 * @member {function} init
 * @member {function} update
 * @member {function} remove
 * @member {function} parse
 * @member {function} stringify
 */
var Component = function (el) {
  var attrs = el.getAttribute(this.name);
  this.el = el;
  this.data = {};
  this.parseAttributes(attrs);
  this.init();
  this.update();
};

Component.prototype = {
  /**
   * Contains default data values.
   * Data is coerced into the types of the values of the defaults.
   */
  defaults: {},

  /**
   * Init handler. Similar to attachedCallback.
   * Called during component initialization and is only run once.
   * Components can use this to set initial state.
   */
  init: function () { /* no-op */ },

  /**
   * Update handler. Similar to attributeChangedCallback.
   * Called whenever component's data changes.
   * Also called on component initialization when the component receives initial data.
   *
   * @param {object} previousData - Previous attributes of the component.
   */
  update: function (previousData) { /* no-op */ },

  /**
   * Remove handler. Similar to detachedCallback.
   * Called whenever component is removed from the entity (i.e., removeAttribute).
   * Components can use this to reset behavior on the entity.
   */
  remove: function () { /* no-op */ },

  /**
   * Describes how the component should deserialize HTML attribute into data.
   * Can be overridden by the component.
   *
   * The default parsing is parsing style-like strings, camelCasing keys for
   * error-tolerance (`max-value` ~= `maxValue`).
   *
   * @param {string} value - HTML attribute.
   * @returns {object} Data.
   */
  parse: function (value) {
    if (typeof value !== 'string') { return value; }
    return transformKeysToCamelCase(styleParser.parse(value));
  },

  /**
   * Describes how the component should serialize data to a string to update the DOM.
   * Can be overridden by the component.
   *
   * The default stringify is to a style-like string.
   *
   * @param {object} data
   * @returns {string}
   */
  stringify: function (data) {
    if (typeof data !== 'object') { return data; }
    return styleParser.stringify(data);
  },

  /**
   * Returns a copy of data such that we don't expose the private this.data.
   *
   * @returns {object} data
   */
  getData: function () {
    var data = this.data;
    if (typeof data !== 'object') { return data; }
    return utils.extend({}, data);
  },

  /**
   * Called when new data is coming from the entity (e.g., attributeChangedCb)
   * or from its mixins. Does some parsing and applying before updating the
   * component.
   * Does not update if data has not changed.
   */
  updateAttributes: function (newData) {
    var previousData = extendWithCheck({}, this.data);
    this.parseAttributes(newData);
    // Don't update if properties haven't changed
    if (utils.deepEqual(previousData, this.data)) { return; }
    this.update(previousData);
  },

  /**
   * Builds component data from the current state of the entity, ultimately
   * updating this.data.
   *
   * If the component was detached completely, set data to null.
   *
   * Precedence:
   * 1. Defaults data
   * 2. Mixin data.
   * 3. Attribute data.
   * Finally coerce the data to the types of the defaults.
   */
  parseAttributes: function (newData) {
    var self = this;
    var data = {};
    var defaults = self.defaults;
    var el = self.el;
    var mixinEls = el.mixinEls;
    var name = self.name;

    // 1. Default values (lowest precendence).
    data = extendWithCheck(data, defaults);

    // 2. Mixin values.
    mixinEls.forEach(applyMixin);
    function applyMixin (mixinEl) {
      var mixinData = mixinEl.getAttribute(name);
      data = extendWithCheck(data, mixinData);
    }

    // 3. Attribute values (highest precendence).
    data = extendWithCheck(data, newData);

    // Coerce to the type of the defaults.
    this.data = utils.coerce(data, defaults);
  }
};

/**
* Object extending, but checks if `source` is an object first.
* If not, `source` is a primitive and we don't do any extending.
*
* @param dest - Destination object or value.
* @param source - Source object or value
* @returns Overridden object or value.
*/
function extendWithCheck (dest, source) {
  var isSourceObject = typeof source === 'object';
  if (source === null) { return dest; }
  if (!isSourceObject) {
    if (source === undefined) { return dest; }
    return source;
  }
  return utils.extend(dest, source);
}

/**
 * Converts string from hyphen to camelCase.
 *
 * @param {string} str - String to camelCase.
 * @return {string} CamelCased string.
 */
function toCamelCase (str) {
  return str.replace(/-([a-z])/g, camelCase);
  function camelCase (g) { return g[1].toUpperCase(); }
}

/**
 * Converts object's keys from hyphens to camelCase (e.g., `max-value` to
 * `maxValue`).
 *
 * @param {object} obj - The object to camelCase keys.
 * @return {object} The object with keys camelCased.
 */
function transformKeysToCamelCase (obj) {
  var keys = Object.keys(obj);
  var camelCaseObj = {};
  keys.forEach(function (key) {
    var camelCaseKey = toCamelCase(key);
    camelCaseObj[camelCaseKey] = obj[key];
  });
  return camelCaseObj;
}

module.exports = Component;
<commit_msg>Adding event that fires when a component changes<commit_after>var styleParser = require('style-attr');
var utils = require('../utils/');

/**
 * Component class definition.
 *
 * Components configure appearance, modify behavior, or add functionality to
 * entities. The behavior and appearance of an entity can be changed at runtime
 * by adding, removing, or updating components. Entities do not share instances
 * of components.
 *
 * @namespace Component
 * @property {object} data - Stores component data, populated by parsing the
 *           attribute name of the component plus applying defaults and mixins.
 * @property {object} el - Reference to the entity element.
 * @property {string} name - Name of the attribute the component is connected
 *           to.
 * @member {Element} el
 * @member {object} data
 * @member {function} getData
 * @member {function} init
 * @member {function} update
 * @member {function} remove
 * @member {function} parse
 * @member {function} stringify
 */
var Component = function (el) {
  var attrs = el.getAttribute(this.name);
  this.el = el;
  this.data = {};
  this.parseAttributes(attrs);
  this.init();
  this.update();
};

Component.prototype = {
  /**
   * Contains default data values.
   * Data is coerced into the types of the values of the defaults.
   */
  defaults: {},

  /**
   * Init handler. Similar to attachedCallback.
   * Called during component initialization and is only run once.
   * Components can use this to set initial state.
   */
  init: function () { /* no-op */ },

  /**
   * Update handler. Similar to attributeChangedCallback.
   * Called whenever component's data changes.
   * Also called on component initialization when the component receives initial data.
   *
   * @param {object} previousData - Previous attributes of the component.
   */
  update: function (previousData) { /* no-op */ },

  /**
   * Remove handler. Similar to detachedCallback.
   * Called whenever component is removed from the entity (i.e., removeAttribute).
   * Components can use this to reset behavior on the entity.
   */
  remove: function () { /* no-op */ },

  /**
   * Describes how the component should deserialize HTML attribute into data.
   * Can be overridden by the component.
   *
   * The default parsing is parsing style-like strings, camelCasing keys for
   * error-tolerance (`max-value` ~= `maxValue`).
   *
   * @param {string} value - HTML attribute.
   * @returns {object} Data.
   */
  parse: function (value) {
    if (typeof value !== 'string') { return value; }
    return transformKeysToCamelCase(styleParser.parse(value));
  },

  /**
   * Describes how the component should serialize data to a string to update the DOM.
   * Can be overridden by the component.
   *
   * The default stringify is to a style-like string.
   *
   * @param {object} data
   * @returns {string}
   */
  stringify: function (data) {
    if (typeof data !== 'object') { return data; }
    return styleParser.stringify(data);
  },

  /**
   * Returns a copy of data such that we don't expose the private this.data.
   *
   * @returns {object} data
   */
  getData: function () {
    var data = this.data;
    if (typeof data !== 'object') { return data; }
    return utils.extend({}, data);
  },

  /**
   * Called when new data is coming from the entity (e.g., attributeChangedCb)
   * or from its mixins. Does some parsing and applying before updating the
   * component.
   * Does not update if data has not changed.
   */
  updateAttributes: function (newData) {
    var previousData = extendWithCheck({}, this.data);
    this.parseAttributes(newData);
    // Don't update if properties haven't changed
    if (utils.deepEqual(previousData, this.data)) { return; }
    this.update(previousData);
    this.el.emit(
      'componentchanged',
      {
        name: this.name,
        newData: this.getData(),
        oldData: previousData
      }
    );
  },

  /**
   * Builds component data from the current state of the entity, ultimately
   * updating this.data.
   *
   * If the component was detached completely, set data to null.
   *
   * Precedence:
   * 1. Defaults data
   * 2. Mixin data.
   * 3. Attribute data.
   * Finally coerce the data to the types of the defaults.
   */
  parseAttributes: function (newData) {
    var self = this;
    var data = {};
    var defaults = self.defaults;
    var el = self.el;
    var mixinEls = el.mixinEls;
    var name = self.name;

    // 1. Default values (lowest precendence).
    data = extendWithCheck(data, defaults);

    // 2. Mixin values.
    mixinEls.forEach(applyMixin);
    function applyMixin (mixinEl) {
      var mixinData = mixinEl.getAttribute(name);
      data = extendWithCheck(data, mixinData);
    }

    // 3. Attribute values (highest precendence).
    data = extendWithCheck(data, newData);

    // Coerce to the type of the defaults.
    this.data = utils.coerce(data, defaults);
  }
};

/**
* Object extending, but checks if `source` is an object first.
* If not, `source` is a primitive and we don't do any extending.
*
* @param dest - Destination object or value.
* @param source - Source object or value
* @returns Overridden object or value.
*/
function extendWithCheck (dest, source) {
  var isSourceObject = typeof source === 'object';
  if (source === null) { return dest; }
  if (!isSourceObject) {
    if (source === undefined) { return dest; }
    return source;
  }
  return utils.extend(dest, source);
}

/**
 * Converts string from hyphen to camelCase.
 *
 * @param {string} str - String to camelCase.
 * @return {string} CamelCased string.
 */
function toCamelCase (str) {
  return str.replace(/-([a-z])/g, camelCase);
  function camelCase (g) { return g[1].toUpperCase(); }
}

/**
 * Converts object's keys from hyphens to camelCase (e.g., `max-value` to
 * `maxValue`).
 *
 * @param {object} obj - The object to camelCase keys.
 * @return {object} The object with keys camelCased.
 */
function transformKeysToCamelCase (obj) {
  var keys = Object.keys(obj);
  var camelCaseObj = {};
  keys.forEach(function (key) {
    var camelCaseKey = toCamelCase(key);
    camelCaseObj[camelCaseKey] = obj[key];
  });
  return camelCaseObj;
}

module.exports = Component;
<|endoftext|>


<commit_before>export default class Component {
  constructor(SL, config={}) {
    if (!SL) {
      throw 'Cannot initialize StampLines component without an SL object!';
    }
    this.SL = SL;
    this.config = config;
  }
  get type() {
    return 'Component';
  }
  configure(config) {
    this.config = config || this.config || {};
    return this.config;
  }
}
<commit_msg>Added default Core.Component.destroy() method<commit_after>export default class Component {
  constructor(SL, config={}) {
    if (!SL) {
      throw 'Cannot initialize StampLines component without an SL object!';
    }
    this.SL = SL;
    this.config = config;
  }
  destroy() {}
  get type() {
    return 'Component';
  }
  configure(config) {
    this.config = config || this.config || {};
    return this.config;
  }
}
<|endoftext|>


<commit_before>import phantom from 'phantom';

import { login as performLogin, analyzeLogin } from '../helpers/login';
import fetch from '../helpers/fetch';

const BASE_URL = 'https://start.telebank.co.il';

const POSSIBLE_LOGIN_URLS = {
  default: `${BASE_URL}/apollo/core/templates/default/masterPage.html#/MY_ACCOUNT_HOMEPAGE`,
  invalidPassword: `${BASE_URL}/LoginPages/Logon?multilang=he&t=P&pagekey=home&bank=d#`,
  changePassword: `${BASE_URL}/LoginPages/Logon`,
};

function notify(options, message) {
  if (options.eventsCallback) {
    options.eventsCallback(message);
  }
}

async function login(page, credentials, options) {
  const loginUrl = `${BASE_URL}/LoginPages/Logon?multilang=he&t=P&pageKey=home&bank=d`;
  const loginFields = [
    { id: 'tzId', value: credentials.id },
    { id: 'tzPassword', value: credentials.password },
    { id: 'aidnum', value: credentials.num },
  ];
  await performLogin(page, loginUrl, loginFields, 'submitButton', () => notify(options, 'discount: logging in'));
}

async function fetchAccountData(page, options) {
  await page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js');

  const apiSiteUrl = `${BASE_URL}/Titan/gatewayAPI`;

  const accountDataUrl = `${apiSiteUrl}/userAccountsData`;
  const accountInfo = await fetch(page, accountDataUrl);
  const accountNumber = accountInfo.UserAccountsData.DefaultAccountNumber;

  notify(options, `discount: found account number ${accountNumber}`);

  const date = new Date();
  date.setDate(date.getDate() - 180);
  const txnsUrl = `${apiSiteUrl}/lastTransactions/${accountNumber}/Date?IsCategoryDescCode=True&IsTransactionDetails=True&IsEventNames=True&FromDate=${date.toISOString().slice(0, 10).replace(/-/g, '')}`;
  const txnsResult = await fetch(page, txnsUrl);
  if (txnsResult.Error) {
    return {
      success: false,
      errorType: 'generic',
      errorMessage: txnsResult.Error.MsgText,
    };
  }
  const txns = txnsResult.CurrentAccountLastTransactions.OperationEntry;

  const accountData = {
    success: true,
    accountNumber,
    txns,
  };
  notify(options, `discount: end scraping for account ${accountData.accountNumber}, found ${accountData.txns.length} transactions`);

  return accountData;
}

async function scrape(credentials, options = {}) {
  notify(options, 'discount: start scraping');

  const instance = await phantom.create();
  const page = await instance.createPage();

  await login(page, credentials, options);

  const loginResult = await analyzeLogin(page, POSSIBLE_LOGIN_URLS);
  if (['timeout', 'generic'].includes(loginResult)) {
    return {
      success: false,
      errorType: loginResult,
    };
  }

  let scrapeResult;
  switch (loginResult) {
    case 'default':
      notify(options, 'discount: login successful');
      scrapeResult = await fetchAccountData(page, options);
      break;
    case 'invalidPassword':
      notify(options, 'discount: invalid password');
      scrapeResult = {
        success: false,
        errorType: loginResult,
      };
      break;
    case 'changePassword':
      notify(options, 'discount: need to change password');
      scrapeResult = {
        success: false,
        errorType: loginResult,
      };
      break;
    default:
      throw new Error('unexpected login result');
  }

  await instance.exit();

  return scrapeResult;
}

export default scrape;
<commit_msg>extract handling login result<commit_after>import phantom from 'phantom';

import { login as performLogin, analyzeLogin } from '../helpers/login';
import fetch from '../helpers/fetch';

const BASE_URL = 'https://start.telebank.co.il';

const POSSIBLE_LOGIN_URLS = {
  default: `${BASE_URL}/apollo/core/templates/default/masterPage.html#/MY_ACCOUNT_HOMEPAGE`,
  invalidPassword: `${BASE_URL}/LoginPages/Logon?multilang=he&t=P&pagekey=home&bank=d#`,
  changePassword: `${BASE_URL}/LoginPages/Logon`,
};

function notify(options, message) {
  if (options.eventsCallback) {
    options.eventsCallback(message);
  }
}

async function login(page, credentials, options) {
  const loginUrl = `${BASE_URL}/LoginPages/Logon?multilang=he&t=P&pageKey=home&bank=d`;
  const loginFields = [
    { id: 'tzId', value: credentials.id },
    { id: 'tzPassword', value: credentials.password },
    { id: 'aidnum', value: credentials.num },
  ];
  await performLogin(page, loginUrl, loginFields, 'submitButton', () => notify(options, 'discount: logging in'));
}

async function fetchAccountData(page, options) {
  await page.includeJs('https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js');

  const apiSiteUrl = `${BASE_URL}/Titan/gatewayAPI`;

  const accountDataUrl = `${apiSiteUrl}/userAccountsData`;
  const accountInfo = await fetch(page, accountDataUrl);
  const accountNumber = accountInfo.UserAccountsData.DefaultAccountNumber;

  notify(options, `discount: found account number ${accountNumber}`);

  const date = new Date();
  date.setDate(date.getDate() - 180);
  const txnsUrl = `${apiSiteUrl}/lastTransactions/${accountNumber}/Date?IsCategoryDescCode=True&IsTransactionDetails=True&IsEventNames=True&FromDate=${date.toISOString().slice(0, 10).replace(/-/g, '')}`;
  const txnsResult = await fetch(page, txnsUrl);
  if (txnsResult.Error) {
    return {
      success: false,
      errorType: 'generic',
      errorMessage: txnsResult.Error.MsgText,
    };
  }
  const txns = txnsResult.CurrentAccountLastTransactions.OperationEntry;

  const accountData = {
    success: true,
    accountNumber,
    txns,
  };
  notify(options, `discount: end scraping for account ${accountData.accountNumber}, found ${accountData.txns.length} transactions`);

  return accountData;
}

async function handleLoginResult(page, options, loginResult) {
  let scrapeResult;
  switch (loginResult) {
    case 'default':
      notify(options, 'discount: login successful');
      scrapeResult = await fetchAccountData(page, options);
      break;
    case 'invalidPassword':
      notify(options, 'discount: invalid password');
      scrapeResult = {
        success: false,
        errorType: loginResult,
      };
      break;
    case 'changePassword':
      notify(options, 'discount: need to change password');
      scrapeResult = {
        success: false,
        errorType: loginResult,
      };
      break;
    default:
      throw new Error(`unexpected login result "${loginResult}"`);
  }

  return scrapeResult;
}

async function scrape(credentials, options = {}) {
  notify(options, 'discount: start scraping');

  const instance = await phantom.create();
  const page = await instance.createPage();

  await login(page, credentials, options);

  const loginResult = await analyzeLogin(page, POSSIBLE_LOGIN_URLS);
  if (['timeout', 'generic'].includes(loginResult)) {
    await instance.exit();
    return {
      success: false,
      errorType: loginResult,
    };
  }

  const scrapeResult = await handleLoginResult(page, options, loginResult);

  await instance.exit();

  return scrapeResult;
}

export default scrape;
<|endoftext|>


<commit_before>/*jshint white: false, strict: false, plusplus: false, onevar: false,
  nomen: false */
/*global define: false, console: false, window: false, setTimeout: false */

define( function ( require ) {

    var Delegate = require( './delegate' );
    var Task = require( './task' );
    var Timer = require( './timer' );
    var Graph = require( 'common/graph' );
    var phases = require( 'core/scheduler-phases' );

    var Scheduler = function( options ) {

        options = options || {};

        var _tasks = {};

        var _phases = {};
        for( var phase in phases ) {
            _phases[phases[phase]] = new Graph();
        }

        // var _queue = new PriorityQueue();
        var _running = false,
            that = this;

        var _previousTime;
        var _tick = new Delegate();    // Time signal, sent each frame

        this.Timer = Timer({ tick: _tick });
        this.Task = Task({ manager: this });

        Object.defineProperty( this, 'phases', {
           get: function() {
               return phases;
           }
        });

        var _realTime = new this.Timer();
        Object.defineProperty( this, 'realTime', {
            get: function() {
                return _realTime;
            }
        });

        var _simulationTime = new this.Timer();
        Object.defineProperty( this, 'simulationTime', {
            get: function() {
                return _simulationTime;
            }
        });

        var _frame = 0;
        Object.defineProperty( this, 'frame', {
            get: function() {
                return _frame;
            }
        });

        var _active = false;
        Object.defineProperty( this, 'active', {
            get: function() {
                return _active;
            }
        });

        this.suspend = function() {
            _active = false;
        };

        this.clear = function() {
            _queue = [];
        };

        this.resume = function() {
            if( !_active ) {
                _active = true;
                if( undefined === _previousTime ) {
                    _previousTime = Date.now();
                }
                if( !_running ) {
                    setTimeout( run, 0 );
                }
            }
        };

        var run = function() {
            if( _active && !_running ) {
                _running = true;

                ++ _frame;

                var delta = Date.now() - _previousTime;
                _previousTime += delta;
                _tick( delta );        // Send tick event
                dispatch();            // Dispatch queued tasks
                if( _active ) {
                    setTimeout( run, 0 );
                }

                _running = false;
            }
        };

        var dispatch = function() {
            for( var phase in _phases ) {
                var dag = _phases[phase];
                var schedule = _phases[phase].sort();

                while( schedule.length > 0 ) {
                    var task = _tasks[schedule.shift()];

                    if( task && task.active ) {
                        task.scheduled = false;
                        try{
                            task.callback();
                        } catch( e ) {
                            // Suspend the scheduler and return
                            that.suspend();
                            return;
                        }

                        if( task.active ) {
                            task.scheduled = true;
                        } else {
                            dag.remove( task.id );
                        }
                    }
                }
            }
        };

        this.add = function( task ) {
            if( !task.scheduled ) {
                task.scheduled = true;
                _tasks[task.id] = task;

                var dag = _phases[task.schedule.phase];

                if( task.group ) {
                    dag.link( task.id, task.group );
                } else {
                    dag.insert( task.id );
                }

                if( task.depends ) {
                    for( var i = 0, l = task.depends.length; i < l; ++ i ) {
                        dag.link( task.depends[i], task.id );
                    }
                }
            }
        };

        this.remove = function( task ) {
            if( task.scheduled && task.manager === this ) {
                task.scheduled = false;

                delete _tasks[task.id];
            }
        };

        if( options.active ) {
            this.resume();
        }

    };

    return Scheduler;

});
<commit_msg>Cleanup.<commit_after>/*jshint white: false, strict: false, plusplus: false, onevar: false,
  nomen: false */
/*global define: false, console: false, window: false, setTimeout: false */

define( function ( require ) {

    var Delegate = require( './delegate' );
    var Task = require( './task' );
    var Timer = require( './timer' );
    var Graph = require( 'common/graph' );
    var phases = require( 'core/scheduler-phases' );

    var Scheduler = function( options ) {

        options = options || {};

        var _tasks = {},
            _phases = {};

        for( var phase in phases ) {
            _phases[phases[phase]] = new Graph();
        }

        var _running = false,
            that = this,
            _previousTime,
            _tick = new Delegate();    // Time signal, sent each frame

        this.Timer = Timer({ tick: _tick });
        this.Task = Task({ manager: this });

        Object.defineProperty( this, 'phases', {
           get: function() {
               return phases;
           }
        });

        var _realTime = new this.Timer();
        Object.defineProperty( this, 'realTime', {
            get: function() {
                return _realTime;
            }
        });

        var _simulationTime = new this.Timer();
        Object.defineProperty( this, 'simulationTime', {
            get: function() {
                return _simulationTime;
            }
        });

        var _frame = 0;
        Object.defineProperty( this, 'frame', {
            get: function() {
                return _frame;
            }
        });

        var _active = false;
        Object.defineProperty( this, 'active', {
            get: function() {
                return _active;
            }
        });

        this.suspend = function() {
            _active = false;
        };

        this.clear = function() {
            _queue = [];
        };

        this.resume = function() {
            if( !_active ) {
                _active = true;
                if( undefined === _previousTime ) {
                    _previousTime = Date.now();
                }
                if( !_running ) {
                    setTimeout( run, 0 );
                }
            }
        };

        var run = function() {
            if( _active && !_running ) {
                _running = true;

                ++ _frame;

                var delta = Date.now() - _previousTime;
                _previousTime += delta;
                _tick( delta );        // Send tick event
                dispatch();            // Dispatch queued tasks
                if( _active ) {
                    setTimeout( run, 0 );
                }

                _running = false;
            }
        };

        var dispatch = function() {
            for( var phase in _phases ) {
                var dag = _phases[phase];
                var schedule = _phases[phase].sort();

                while( schedule.length > 0 ) {
                    var task = _tasks[schedule.shift()];

                    if( task && task.active ) {
                        task.scheduled = false;
                        try{
                            task.callback();
                        } catch( e ) {
                            // Suspend the scheduler and return
                            that.suspend();
                            return;
                        }

                        if( task.active ) {
                            task.scheduled = true;
                        } else {
                            dag.remove( task.id );
                        }
                    }
                }
            }
        };

        this.add = function( task ) {
            if( !task.scheduled ) {
                task.scheduled = true;
                _tasks[task.id] = task;

                var dag = _phases[task.schedule.phase];

                if( task.group ) {
                    dag.link( task.id, task.group );
                } else {
                    dag.insert( task.id );
                }

                if( task.depends ) {
                    for( var i = 0, l = task.depends.length; i < l; ++ i ) {
                        dag.link( task.depends[i], task.id );
                    }
                }
            }
        };

        this.remove = function( task ) {
            if( task.scheduled && task.manager === this ) {
                task.scheduled = false;

                delete _tasks[task.id];
            }
        };

        if( options.active ) {
            this.resume();
        }

    };

    return Scheduler;

});
<|endoftext|>