<commit_before>describe("Interpreter()" +
".nonTerminalAlternative([symbol1, ... , symbolN, ... symbolM])" +
".parse(lexemeK + code)", function() {

  var methodFactory = Interpreter.MethodFactory();

  it("if k = m = 1, calls symbol1 with codePointer",
  function() {
    var actuallThisBinding = {con: "value 0"};
    var symbol1 = jasmine.createSpy("symbol 1").and
    .returnValue(function() {});
    var alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    actuallThisBinding.method = alternative(codePointer);
    actuallThisBinding.method();
    expect(symbol1)
    .toHaveBeenCalledWith(codePointer);
  });

  it("if k = m = 1, returns the reslut of calling symbol1 and updates codePointer", function() {
    var actuallThisBinding = {con: "value 0"};
    var symbol1 = StubLexeme_dConcatenator();
    var alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    actuallThisBinding.method = alternative(codePointer);
    expect(codePointer.getUnparsed()).toEqual("code");
    actuallThisBinding.method();
    expect(actuallThisBinding.con).toEqual("value 0" + "lexeme 1");
  });

  it("if k = m = 1, calls symbol1 with codePointer and " +
  "Interpreter.JUST_MAKE_INSTRUCTION", function() {
    var symbol1 = jasmine.createSpy("symbol 1");
    var alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    alternative(codePointer);
    expect(symbol1).toHaveBeenCalledWith(codePointer);
  });

  it("if k = m = 2, returns result of calling symbol2", function() {
    var actuallThisBinding = {con: "value 0"};
    var symbol1 = jasmine.createSpy("symbol1").and.returnValue(null);
    var symbol2 = StubLexeme_dConcatenator();
    var alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 2" + "code");
    actuallThisBinding.method = alternative(codePointer);
    actuallThisBinding.method();
    expect(actuallThisBinding.con).toEqual("value 0" + "lexeme 2");
  });

  function UnsuccessfulEaterOfChars() {
    function instructionMaker(codePointer) {
      codePointer.restore(codePointer.getUnparsed().slice(1));
      return null;
    }

    return Interpreter.MethodFactory().symbol(instructionMaker);
  }

  it("if k = m = 2 calls symbol2.parse with lexeme2 + code, even if " +
  "symbol1 has moved the unparsedCodePointer before it failed",
  function() {
    var symbol1 = UnsuccessfulEaterOfChars();
    var actuallThisBinding = {con: "value 0"};
    var symbol2 = StubLexeme_dConcatenator();
    var alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 2" + "code");
    actuallThisBinding.method = alternative(codePointer);
    actuallThisBinding.method();
    expect(actuallThisBinding.con).toEqual("value 0" + "lexeme 2");
  });

  it("if k = 1 and m = 2, moves unparsedCodePointer past lexeme1",
  function() {
    var symbol1 = StubLexeme_dConcatenator();
    var actuallThisBinding = {con: "value 0"};
    var symbol2 = UnsuccessfulEaterOfChars();
    var alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    alternative(codePointer)();
    expect(codePointer.getUnparsed()).toEqual("code");
  });

  it("calls symbol 1 with the same this binding", function() {
        var thisBinding = {binding: "this"};
    var stolenThis;
    var thisThief = function() {
      stolenThis = this;
      return function() {};
    };

    thisBinding.method = methodFactory.nonTerminalAlternative([thisThief]);

    thisBinding.method(CodePointer());
    expect(stolenThis).toBe(thisBinding);

  });

});
<commit_msg>nonTerminalAlternative returns methods, not functions.<commit_after>describe("Interpreter.MethodFactory()" +
".nonTerminalAlternative([symbol1, ... , symbolN, ... symbolM])" +
".call(interpreter, lexemeK + code).call(interpreter)", function() {

  var methodFactory;
  var interpreter;

  beforeEach(function() {
    methodFactory = Interpreter.MethodFactory();
    interpreter = {con: "value 0"};
  });

  it("if k = m = 1, calls symbol1 with codePointer",
  function() {
    var actuallThisBinding = {con: "value 0"};
    var symbol1 = jasmine.createSpy("symbol 1").and
    .returnValue(function() {});
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    interpreter.alternative(codePointer);
    expect(symbol1)
    .toHaveBeenCalledWith(codePointer);
  });

  it("if k = m = 1, returns the reslut of calling symbol1 and updates codePointer", function() {
    var symbol1 = StubLexeme_dConcatenator();
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    var instruction = interpreter.alternative(codePointer);
    expect(codePointer.getUnparsed()).toEqual("code");
    instruction.call(interpreter);
    expect(interpreter.con).toEqual("value 0" + "lexeme 1");
  });

  it("if k = m = 1, calls symbol1 with codePointer", function() {
    var symbol1 = jasmine.createSpy("symbol 1");
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    interpreter.alternative(codePointer);
    expect(symbol1).toHaveBeenCalledWith(codePointer);
  });

  it("if k = m = 2, returns result of calling symbol2", function() {
    var symbol1 = jasmine.createSpy("symbol1").and.returnValue(null);
    var symbol2 = StubLexeme_dConcatenator();
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 2" + "code");
    interpreter.method = interpreter.alternative(codePointer);
    interpreter.method();
    expect(interpreter.con).toEqual("value 0" + "lexeme 2");
  });

  function UnsuccessfulEaterOfChars() {
    function instructionMaker(codePointer) {
      codePointer.restore(codePointer.getUnparsed().slice(1));
      return null;
    }

    return Interpreter.MethodFactory().symbol(instructionMaker);
  }

  it("if k = m = 2 calls symbol2.parse with lexeme2 + code, even if " +
  "symbol1 has moved the unparsedCodePointer before it failed",
  function() {
    var symbol1 = UnsuccessfulEaterOfChars();
    var actuallThisBinding = {con: "value 0"};
    var symbol2 = StubLexeme_dConcatenator();
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 2" + "code");
    actuallThisBinding.method = interpreter.alternative(codePointer);
    actuallThisBinding.method();
    expect(actuallThisBinding.con).toEqual("value 0" + "lexeme 2");
  });

  it("if k = 1 and m = 2, moves unparsedCodePointer past lexeme1",
  function() {
    var symbol1 = StubLexeme_dConcatenator();
    var actuallThisBinding = {con: "value 0"};
    var symbol2 = UnsuccessfulEaterOfChars();
    interpreter.alternative = methodFactory.nonTerminalAlternative([symbol1, symbol2]);
    var codePointer = StubCodePointer("lexeme 1" + "code");
    interpreter.alternative(codePointer)();
    expect(codePointer.getUnparsed()).toEqual("code");
  });

  it("calls symbol 1 with the same this binding", function() {
        var thisBinding = {binding: "this"};
    var stolenThis;
    var thisThief = function() {
      stolenThis = this;
      return function() {};
    };

    thisBinding.method = methodFactory.nonTerminalAlternative([thisThief]);

    thisBinding.method(CodePointer());
    expect(stolenThis).toBe(thisBinding);

  });

});
<|endoftext|>


<commit_before>import React from 'react';

/*

Turns a React element into its JSX string representation.

Probably not complete

Features:

- Uses self-closing tags when no children are set
- Uses a single line for one/none prop
- Uses multiple lines for multiple props
- Sorts props alphabetically
- Removes defaultProps from output

Needs work:

- Don't use JSON.stringify: Nested objects are rendered as JSON (e.g.
)

*/

const reactElementToString = (el, indent = '') => {
  if (el === void 0) {
    return '';
  }

  if (typeof el === 'string') {
    return `${indent}${el}`;
  }

  const {props, type} = el;
  let displayName = '';
  let defaultProps = null;

  if (typeof type === 'string') {
    displayName = type;
  } else {
    displayName = type.displayName;
    defaultProps = type.defaultProps;
  }

  const formatProp = (k, v) => {
    return v === true ? k :
      typeof v === 'string' ? `${k}='${v}'` :
      React.isValidElement(v) ? `${k}={${reactElementToString(v)}}` :
      `${k}={${JSON.stringify(v) || v.name || typeof v}}`;
  };

  const propKeys = Object.keys(props)
    .sort()
    .filter((k) => k !== 'children')
    .filter((k) => defaultProps ? props[k] !== defaultProps[k] : true);

  const propString = propKeys.map((k) => formatProp(k, props[k])).join(`\n${indent}  `);

  const whitespaceBeforeProps = propKeys.length > 1 ? `\n${indent}  ` :
    propKeys.length === 1 ? ' ' :
    '';
  const whitespaceAfterProps = propKeys.length > 1 ? `\n${indent}` : '';

  return props.children ?
`${indent}<${displayName}${whitespaceBeforeProps}${propString}${whitespaceAfterProps}>
${React.Children.map(props.children, (c) => reactElementToString(c, `${indent}  `)).join('\n')}
${indent}</${displayName}>` :
`${indent}<${displayName}${whitespaceBeforeProps}${propString}${whitespaceAfterProps} />`;
};

export default reactElementToString;
<commit_msg>Fix `undefined` stateless component names<commit_after>import React from 'react';

/*

Turns a React element into its JSX string representation.

Probably not complete

Features:

- Uses self-closing tags when no children are set
- Uses a single line for one/none prop
- Uses multiple lines for multiple props
- Sorts props alphabetically
- Removes defaultProps from output

Needs work:

- Don't use JSON.stringify: Nested objects are rendered as JSON (e.g.
)

*/

const reactElementToString = (el, indent = '') => {
  if (el === void 0) {
    return '';
  }

  if (typeof el === 'string') {
    return `${indent}${el}`;
  }

  const {props, type} = el;
  let displayName = '';
  let defaultProps = null;

  if (typeof type === 'string') {
    displayName = type;
  } else {
    displayName = type.displayName || type.name;
    defaultProps = type.defaultProps;
  }

  const formatProp = (k, v) => {
    return v === true ? k :
      typeof v === 'string' ? `${k}='${v}'` :
      React.isValidElement(v) ? `${k}={${reactElementToString(v)}}` :
      `${k}={${JSON.stringify(v) || v.name || typeof v}}`;
  };

  const propKeys = Object.keys(props)
    .sort()
    .filter((k) => k !== 'children')
    .filter((k) => defaultProps ? props[k] !== defaultProps[k] : true);

  const propString = propKeys.map((k) => formatProp(k, props[k])).join(`\n${indent}  `);

  const whitespaceBeforeProps = propKeys.length > 1 ? `\n${indent}  ` :
    propKeys.length === 1 ? ' ' :
    '';
  const whitespaceAfterProps = propKeys.length > 1 ? `\n${indent}` : '';

  return props.children ?
`${indent}<${displayName}${whitespaceBeforeProps}${propString}${whitespaceAfterProps}>
${React.Children.map(props.children, (c) => reactElementToString(c, `${indent}  `)).join('\n')}
${indent}</${displayName}>` :
`${indent}<${displayName}${whitespaceBeforeProps}${propString}${whitespaceAfterProps} />`;
};

export default reactElementToString;
<|endoftext|>


<commit_before>const EventEmitter = require('events')
const {dirname, resolve} = require('path')
const Board = require('@sabaki/go-board')
const {Controller, ControllerStateTracker, Command} = require('@sabaki/gtp')
const sgf = require('@sabaki/sgf')
const argvsplit = require('argv-split')
const gametree = require('./gametree')
const helper = require('./helper')

const alpha = 'ABCDEFGHJKLMNOPQRSTUVWXYZ'

function parseVertex(coord, size) {
    if (coord == null || coord === 'resign') return null
    if (coord === 'pass') return [-1, -1]

    let x = alpha.indexOf(coord[0].toUpperCase())
    let y = size - +coord.slice(1)

    return [x, y]
}

class EngineSyncer extends EventEmitter {
    constructor(engine) {
        super()

        let {path, args, commands} = engine

        this._busy = false
        this.engine = engine
        this.commands = []

        this.controller = new Controller(path, argvsplit(args), {
            cwd: dirname(resolve(path))
        })
        this.stateTracker = new ControllerStateTracker(this.controller)

        this.controller.on('started', () => {
            Promise.all([
                this.controller.sendCommand({name: 'name'}),
                this.controller.sendCommand({name: 'version'}),
                this.controller.sendCommand({name: 'protocol_version'}),
                this.controller.sendCommand({name: 'list_commands'}).then(response => {
                    this.commands = response.content.split('\n')
                }),
                ...(
                    commands != null
                    && commands.trim() !== ''
                    ? commands.split(';').filter(x => x.trim() !== '').map(command =>
                        this.controller.sendCommand(Command.fromString(command))
                    )
                    : []
                )
            ]).catch(helper.noop)
        })

        // Sync busy property

        for (let eventName of ['stopped', 'command-sent', 'response-received']) {
            this.controller.on(eventName, () => {
                this.busy = this.controller.busy
            })
        }
    }

    get state() {
        return this.stateTracker.state
    }

    get busy() {
        return this._busy
    }

    set busy(value) {
        if (value !== this._busy) {
            this._busy = value
            this.emit('busy-changed')
        }
    }

    async sync(tree, id) {
        let board = gametree.getBoard(tree, id)

        if (!board.isSquare()) {
            throw new Error('GTP engines don’t support non-square boards.')
        } else if (!board.isValid()) {
            throw new Error('GTP engines don’t support invalid board positions.')
        } else if (board.width > alpha.length) {
            throw new Error(`GTP engines only support board sizes that don’t exceed ${alpha.length}.`)
        }

        let komi = +gametree.getRootProperty(tree, 'KM', 0)
        let boardsize = board.width;

        // Replay

        let engineBoard = Board.fromDimensions(board.width, board.height)
        let history = []
        let boardSynced = true
        let nodes = [...tree.listNodesVertically(id, -1, {})].reverse()

        for (let node of nodes) {
            let nodeBoard = gametree.getBoard(tree, node.id)
            let placedHandicapStones = false

            if (
                node.data.AB
                && node.data.AB.length >= 2
                && engineBoard.isEmpty()
                && await this.stateTracker.knowsCommand('set_free_handicap')
            ) {
                // Place handicap stones

                let vertices = [].concat(...node.data.AB.map(sgf.parseCompressedVertices)).sort()
                let coords = vertices
                    .map(v => board.stringifyVertex(v))
                    .filter(x => x != null)
                    .filter((x, i, arr) => i === 0 || x !== arr[i - 1])

                if (coords.length > 0) {
                    history.push({name: 'set_free_handicap', args: coords})

                    for (let vertex of vertices) {
                        if (engineBoard.get(vertex) !== 0) continue

                        engineBoard = engineBoard.makeMove(1, vertex)
                    }

                    placedHandicapStones = true
                }
            }

            for (let prop of ['B', 'W', 'AB', 'AW']) {
                if (node.data[prop] == null || placedHandicapStones && prop === 'AB') continue

                let color = prop.slice(-1)
                let sign = color === 'B' ? 1 : -1
                let vertices = [].concat(...node.data[prop].map(sgf.parseCompressedVertices))

                for (let vertex of vertices) {
                    if (engineBoard.has(vertex) && engineBoard.get(vertex) !== 0) continue
                    else if (!engineBoard.has(vertex)) vertex = [-1, -1]

                    let coord = board.stringifyVertex(vertex)

                    history.push({name: 'play', args: [color, coord]})
                    engineBoard = engineBoard.makeMove(sign, vertex)
                }
            }

            if (!helper.equals(engineBoard.signMap, nodeBoard.signMap)) {
                boardSynced = false
                break
            }
        }

        // Incremental rearrangement

        if (!boardSynced) {
            history = [...this.state.history]
            engineBoard = Board.fromDimensions(board.width, board.height)

            for (let command of this.state.history) {
                if (command.name === 'play') {
                    let [color, coord] = command.args
                    let sign = color.toUpperCase() === 'B' ? 1 : -1

                    engineBoard = engineBoard.makeMove(sign, parseVertex(coord, boardsize))
                } else if (command.name === 'set_free_handicap') {
                    for (let coord of command.args) {
                        engineBoard = engineBoard.makeMove(1, parseVertex(coord, boardsize))
                    }
                }
            }

            let diff = engineBoard.diff(board).filter(v => board.get(v) !== 0)

            for (let vertex of diff) {
                let sign = board.get(vertex)
                let color = sign > 0 ? 'B' : 'W'
                let coord = board.stringifyVertex(vertex)

                history.push({name: 'play', args: [color, coord]})
                engineBoard = engineBoard.makeMove(sign, vertex)
            }

            if (helper.equals(engineBoard.signMap, board.signMap)) {
                boardSynced = true
            }
        }

        // Complete rearrangement

        if (!boardSynced) {
            history = []
            engineBoard = Board.fromDimensions(board.width, board.height)

            for (let x = 0; x < board.width; x++) {
                for (let y = 0; y < board.height; y++) {
                    let vertex = [x, y]
                    let sign = board.get(vertex)
                    let color = sign > 0 ? 'B' : 'W'
                    if (sign === 0) continue

                    history.push({name: 'play', args: [color, board.stringifyVertex(vertex)]})
                    engineBoard = engineBoard.makeMove(sign, vertex)
                }
            }

            if (helper.equals(engineBoard.signMap, board.signMap)) {
                boardSynced = true
            }
        }

        if (!boardSynced) {
            throw new Error('Current board arrangement can’t be recreated on the GTP engine.')
        }

        try {
            await this.stateTracker.sync({komi, boardsize, history})
        } catch (err) {
            throw new Error('GTP engine can’t be synced to current state.')
        }
    }
}

module.exports = EngineSyncer
<commit_msg>Make engine syncing faster<commit_after>const EventEmitter = require('events')
const {dirname, resolve} = require('path')
const Board = require('@sabaki/go-board')
const {Controller, ControllerStateTracker, Command} = require('@sabaki/gtp')
const sgf = require('@sabaki/sgf')
const argvsplit = require('argv-split')
const gametree = require('./gametree')
const helper = require('./helper')

const alpha = 'ABCDEFGHJKLMNOPQRSTUVWXYZ'

function parseVertex(coord, size) {
    if (coord == null || coord === 'resign' || coord === 'pass') return [-1, -1]

    let x = alpha.indexOf(coord[0].toUpperCase())
    let y = size - +coord.slice(1)

    return [x, y]
}

class EngineSyncer extends EventEmitter {
    constructor(engine) {
        super()

        let {path, args, commands} = engine

        this._busy = false
        this.engine = engine
        this.commands = []

        this.controller = new Controller(path, argvsplit(args), {
            cwd: dirname(resolve(path))
        })
        this.stateTracker = new ControllerStateTracker(this.controller)

        this.controller.on('started', () => {
            Promise.all([
                this.controller.sendCommand({name: 'name'}),
                this.controller.sendCommand({name: 'version'}),
                this.controller.sendCommand({name: 'protocol_version'}),
                this.controller.sendCommand({name: 'list_commands'}).then(response => {
                    this.commands = response.content.split('\n')
                }),
                ...(
                    commands != null
                    && commands.trim() !== ''
                    ? commands.split(';').filter(x => x.trim() !== '').map(command =>
                        this.controller.sendCommand(Command.fromString(command))
                    )
                    : []
                )
            ]).catch(helper.noop)
        })

        // Sync busy property

        for (let eventName of ['stopped', 'command-sent', 'response-received']) {
            this.controller.on(eventName, () => {
                this.busy = this.controller.busy
            })
        }
    }

    get state() {
        return this.stateTracker.state
    }

    get busy() {
        return this._busy
    }

    set busy(value) {
        if (value !== this._busy) {
            this._busy = value
            this.emit('busy-changed')
        }
    }

    async sync(tree, id) {
        let board = gametree.getBoard(tree, id)

        if (!board.isSquare()) {
            throw new Error('GTP engines don’t support non-square boards.')
        } else if (!board.isValid()) {
            throw new Error('GTP engines don’t support invalid board positions.')
        } else if (board.width > alpha.length) {
            throw new Error(`GTP engines only support board sizes that don’t exceed ${alpha.length}.`)
        }

        let komi = +gametree.getRootProperty(tree, 'KM', 0)
        let boardsize = board.width;

        // Replay

        let nodeBoard = gametree.getBoard(tree, id)
        let engineBoard = Board.fromDimensions(board.width, board.height)
        let history = []
        let boardSynced = true
        let nodes = [...tree.listNodesVertically(id, -1, {})].reverse()

        for (let node of nodes) {
            let placedHandicapStones = false

            if (
                node.data.AB
                && node.data.AB.length >= 2
                && engineBoard.isEmpty()
                && await this.stateTracker.knowsCommand('set_free_handicap')
            ) {
                // Place handicap stones

                let vertices = [].concat(...node.data.AB.map(sgf.parseCompressedVertices)).sort()
                let coords = vertices
                    .map(v => board.stringifyVertex(v))
                    .filter(x => x != null)
                    .filter((x, i, arr) => i === 0 || x !== arr[i - 1])

                if (coords.length > 0) {
                    history.push({name: 'set_free_handicap', args: coords})

                    for (let vertex of vertices) {
                        if (engineBoard.get(vertex) !== 0) continue

                        engineBoard = engineBoard.makeMove(1, vertex)
                    }

                    placedHandicapStones = true
                }
            }

            for (let prop of ['B', 'W', 'AB', 'AW']) {
                if (node.data[prop] == null || placedHandicapStones && prop === 'AB') continue

                let color = prop.slice(-1)
                let sign = color === 'B' ? 1 : -1
                let vertices = [].concat(...node.data[prop].map(sgf.parseCompressedVertices))

                for (let vertex of vertices) {
                    if (engineBoard.has(vertex) && engineBoard.get(vertex) !== 0) continue
                    else if (!engineBoard.has(vertex)) vertex = [-1, -1]

                    let coord = board.stringifyVertex(vertex)

                    history.push({name: 'play', args: [color, coord]})
                    engineBoard = engineBoard.makeMove(sign, vertex)
                }
            }
        }

        if (!helper.equals(engineBoard.signMap, nodeBoard.signMap)) {
            boardSynced = false
            break
        }

        // Incremental rearrangement

        if (!boardSynced) {
            history = [...this.state.history]
            engineBoard = Board.fromDimensions(board.width, board.height)

            for (let command of this.state.history) {
                if (command.name === 'play') {
                    let [color, coord] = command.args
                    let sign = color.toUpperCase() === 'B' ? 1 : -1

                    engineBoard = engineBoard.makeMove(sign, parseVertex(coord, boardsize))
                } else if (command.name === 'set_free_handicap') {
                    for (let coord of command.args) {
                        engineBoard = engineBoard.makeMove(1, parseVertex(coord, boardsize))
                    }
                }
            }

            let diff = engineBoard.diff(board).filter(v => board.get(v) !== 0)

            for (let vertex of diff) {
                let sign = board.get(vertex)
                let color = sign > 0 ? 'B' : 'W'
                let coord = board.stringifyVertex(vertex)

                history.push({name: 'play', args: [color, coord]})
                engineBoard = engineBoard.makeMove(sign, vertex)
            }

            if (helper.equals(engineBoard.signMap, board.signMap)) {
                boardSynced = true
            }
        }

        // Complete rearrangement

        if (!boardSynced) {
            history = []
            engineBoard = Board.fromDimensions(board.width, board.height)

            for (let x = 0; x < board.width; x++) {
                for (let y = 0; y < board.height; y++) {
                    let vertex = [x, y]
                    let sign = board.get(vertex)
                    let color = sign > 0 ? 'B' : 'W'
                    if (sign === 0) continue

                    history.push({name: 'play', args: [color, board.stringifyVertex(vertex)]})
                    engineBoard = engineBoard.makeMove(sign, vertex)
                }
            }

            if (helper.equals(engineBoard.signMap, board.signMap)) {
                boardSynced = true
            }
        }

        if (!boardSynced) {
            throw new Error('Current board arrangement can’t be recreated on the GTP engine.')
        }

        try {
            await this.stateTracker.sync({komi, boardsize, history})
        } catch (err) {
            throw new Error('GTP engine can’t be synced to current state.')
        }
    }
}

module.exports = EngineSyncer
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Math.sign = function(n) { return n > 0 ? 1 : -1; };

MODEL({
  name: 'Physical',
  properties: [
    { model_: 'FloatProperty', name: 'vx',   defaultValue: 0 },
    { model_: 'FloatProperty', name: 'vy',   defaultValue: 0 },
    {
      model_: 'FloatProperty',
      name: 'velocity',
      getter: function() { return Movement.distance(this.vx, this.vy); },
      setter: function(v) { this.setVelocityAndAngle(v, this.angleOfVelocity); }
    },
    {
      model_: 'FloatProperty',
      name: 'angleOfVelocity',
      getter: function() { return Math.atan2(this.vy, this.vx); },
      setter: function(a) { this.setVelocityAndAngle(this.velocity, a); }
    },
    { model_: 'FloatProperty', name: 'mass', defaultValue: 1 }
  ],
  methods: {
    INFINITE_MASS: 10000,

    intersects: function(c) {
      return Movement.distance(this.x-c.x, this.y-c.y) <= this.r + c.r;
    },
    applyMomentum: function(m, a) {
      this.vx += (m * Math.cos(a) / this.mass);
      this.vy += (m * Math.sin(a) / this.mass);
    },
    momentumAtAngle: function(a) {
      if ( this.mass == this.INFINITE_MASS ) return 0;
      var v = this.velocityAtAngle(a);
      return v * this.mass;
    },
    velocityAtAngle: function(a) {
      if ( this.mass == this.INFINITE_MASS ) return 0;
      return Math.cos(a-this.angleOfVelocity) * this.velocity;
    },
    setVelocityAndAngle: function(v, a) {
      this.vx = v * Math.cos(a);
      this.vy = v * Math.sin(a);
    },
    distanceTo: function(other) {
      return Movement.distance(this.x-other.x, this.y-other.y);
    }
  }
});

/** Collision detection manager. **/
MODEL({
  name: 'Collider',
  properties: [
    { name: 'children', factory: function() { return []; } }
  ],
  listeners: [
    {
      name: 'tick',
      code: function () {
        this.detectCollisions();
        this.start();
      }
    }
  ],
  methods: {
    start: function() {
      this.__ctx__.requestAnimationFrame(this.tick);
    },
    // TODO: this should be done much more efficiently (quad-tree, k-d tree, or similar).
    detectCollisions: function() {
      var cs = this.children;
      for ( var i = 0 ; i < cs.length ; i++ ) {
        var c1 = cs[i];
        for ( var j = i+1 ; j < cs.length ; j++ ) {
          var c2 = cs[j];
          if ( c1.intersects(c2) ) this.collide(c1, c2);
        }
      }
    },
    backup: function(c1, c2) {
      for ( var i = 0.01 ; ; i += 0.1 ) {
        var x1 = c1.x - c1.vx * i;
        var y1 = c1.y - c1.vy * i;
        var x2 = c2.x - c2.vx * i;
        var y2 = c2.y - c2.vy * i;

        if ( Movement.distance(x1-x2, y1-y2) > c1.r + c2.r || i >= 1 ) {
          c1.x = x1; c1.y = y1;
          c2.x = x2; c2.y = y2;
          return;
        }
      }
    },
    collide: function(c1, c2) {
//      this.backup(c1, c2);  // backup to the point of collision

      var a  = Math.atan2(c2.y-c1.y, c2.x-c1.x);
      var m1 =  c1.momentumAtAngle(a);
      var m2 = -c2.momentumAtAngle(a);
      var m  = 2 * ( m1 + m2 );

      // ensure a minimum amount of momentum to that objects don't overlap
      m = Math.max(0.1, m);
      var tMass = c1.mass + c2.mass;
      c1.applyMomentum(-m * c2.mass/tMass, a);
      c2.applyMomentum(m * c1.mass/tMass, a);
    },

    // add one or more components to be monitored for collisions
    add: function() {
      for ( var i = 0 ; i < arguments.length ; i++ )
        this.children.push(arguments[i]);
    }
  }
});

<commit_msg>Moved INFINITE_MASS to constants: block.<commit_after>/**
 * @license
 * Copyright 2014 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Math.sign = function(n) { return n > 0 ? 1 : -1; };

MODEL({
  name: 'Physical',
  properties: [
    { model_: 'FloatProperty', name: 'vx',   defaultValue: 0 },
    { model_: 'FloatProperty', name: 'vy',   defaultValue: 0 },
    {
      model_: 'FloatProperty',
      name: 'velocity',
      getter: function() { return Movement.distance(this.vx, this.vy); },
      setter: function(v) { this.setVelocityAndAngle(v, this.angleOfVelocity); }
    },
    {
      model_: 'FloatProperty',
      name: 'angleOfVelocity',
      getter: function() { return Math.atan2(this.vy, this.vx); },
      setter: function(a) { this.setVelocityAndAngle(this.velocity, a); }
    },
    { model_: 'FloatProperty', name: 'mass', defaultValue: 1 }
  ],

  constants: {
    INFINITE_MASS: 10000
  },

  methods: {
    intersects: function(c) {
      return Movement.distance(this.x-c.x, this.y-c.y) <= this.r + c.r;
    },
    applyMomentum: function(m, a) {
      this.vx += (m * Math.cos(a) / this.mass);
      this.vy += (m * Math.sin(a) / this.mass);
    },
    momentumAtAngle: function(a) {
      if ( this.mass == this.INFINITE_MASS ) return 0;
      var v = this.velocityAtAngle(a);
      return v * this.mass;
    },
    velocityAtAngle: function(a) {
      if ( this.mass == this.INFINITE_MASS ) return 0;
      return Math.cos(a-this.angleOfVelocity) * this.velocity;
    },
    setVelocityAndAngle: function(v, a) {
      this.vx = v * Math.cos(a);
      this.vy = v * Math.sin(a);
    },
    distanceTo: function(other) {
      return Movement.distance(this.x-other.x, this.y-other.y);
    }
  }
});

/** Collision detection manager. **/
MODEL({
  name: 'Collider',
  properties: [
    { name: 'children', factory: function() { return []; } }
  ],
  listeners: [
    {
      name: 'tick',
      code: function () {
        this.detectCollisions();
        this.start();
      }
    }
  ],
  methods: {
    start: function() {
      this.__ctx__.requestAnimationFrame(this.tick);
    },
    // TODO: this should be done much more efficiently (quad-tree, k-d tree, or similar).
    detectCollisions: function() {
      var cs = this.children;
      for ( var i = 0 ; i < cs.length ; i++ ) {
        var c1 = cs[i];
        for ( var j = i+1 ; j < cs.length ; j++ ) {
          var c2 = cs[j];
          if ( c1.intersects(c2) ) this.collide(c1, c2);
        }
      }
    },
    backup: function(c1, c2) {
      for ( var i = 0.01 ; ; i += 0.1 ) {
        var x1 = c1.x - c1.vx * i;
        var y1 = c1.y - c1.vy * i;
        var x2 = c2.x - c2.vx * i;
        var y2 = c2.y - c2.vy * i;

        if ( Movement.distance(x1-x2, y1-y2) > c1.r + c2.r || i >= 1 ) {
          c1.x = x1; c1.y = y1;
          c2.x = x2; c2.y = y2;
          return;
        }
      }
    },
    collide: function(c1, c2) {
//      this.backup(c1, c2);  // backup to the point of collision

      var a  = Math.atan2(c2.y-c1.y, c2.x-c1.x);
      var m1 =  c1.momentumAtAngle(a);
      var m2 = -c2.momentumAtAngle(a);
      var m  = 2 * ( m1 + m2 );

      // ensure a minimum amount of momentum to that objects don't overlap
      m = Math.max(0.1, m);
      var tMass = c1.mass + c2.mass;
      c1.applyMomentum(-m * c2.mass/tMass, a);
      c2.applyMomentum(m * c1.mass/tMass, a);
    },

    // add one or more components to be monitored for collisions
    add: function() {
      for ( var i = 0 ; i < arguments.length ; i++ )
        this.children.push(arguments[i]);
    }
  }
});

<|endoftext|>


<commit_before>define( ['dojo/_base/declare',
         'dojo/_base/array',
         'JBrowse/View/Track/Wiggle',
         'JBrowse/Util'
        ],
        function( declare, array, Wiggle, Util ) {

// feature class for the features we make for the calculated coverage
// values
var CoverageFeature = Util.fastDeclare(
    {
        get: function(f) { return this[f]; },
        tags: function() { return [ 'start', 'end', 'score' ]; },
        score: 0,
        constructor: function( args ) {
            this.start = args.start;
            this.end = args.end;
            this.score = args.score;
        }
    });

return declare( Wiggle,
{

    _defaultConfig: function() {
        return Util.deepUpdate(
            dojo.clone( this.inherited(arguments) ),
            {
                min_score: 0,
                max_score: 100
            }
        );
    },

    getGlobalStats: function() {
        return {};
    },

    getFeatures: function( query, featureCallback, finishCallback, errorCallback ) {
        var leftBase  = query.start;
        var rightBase = query.end;
        var scale = query.scale; // px/bp
        var widthBp = rightBase-leftBase;
        var widthPx = widthBp * ( query.scale || 1/query.basesPerSpan);

        var binWidth = Math.ceil( query.basesPerSpan ); // in bp

        var coverageBins = {};
        var bpToBin = function( bp ) {
            return Math.floor( (bp-leftBase) / binWidth );
        };

        this.store.getFeatures(
            query,
            dojo.hitch( this, function( feature ) {
                            var startBin = bpToBin( feature.get('start') );
                            var endBin   = bpToBin( feature.get('end')-1 );
                            for( var i = startBin; i <= endBin; i++ ) {
                                if ( coverageBins[i] ) {
                                    coverageBins[i]['matchCoverage']++;
                                }
                                else {
                                    coverageBins[i] = {};
                                    coverageBins[i]['matchCoverage'] = 1;
                                }
                            }
                            // Calculate SNP coverage
                            var mdTag = feature.get('MD');
                            if(mdTag) {
                                var SNPs = this._mdToMismatches(feature, mdTag);
                                // loops through mismatches and updates coverage variables accordingly.
                                for (var i = 0; i<SNPs.length; i++) {
                                    var pos = bpToBin( feature.get('start') + SNPs[i].start );
                                    // Note: we reduce matchCoverage so the sum is the total coverage
                                    coverageBins[pos]['matchCoverage']--;
                                    if ( coverageBins[pos][SNPs[i].bases] ) {
                                        coverageBins[pos][SNPs[i].bases]++;
                                    }
                                    else {
                                        coverageBins[pos][SNPs[i].bases] = 1;
                                    }
                                }
                            }
                        }),
            function () {
                // make fake features from the coverage
                for( var i = 0; i < Math.ceil( widthBp/binWidth ); i++ ) {
                    var bpOffset = leftBase+binWidth*i;
                    featureCallback( new CoverageFeature({
                        start: bpOffset,
                        end:   bpOffset+binWidth,
                        score: coverageBins[i] || {'matchCoverage': 0}
                     }));
                }
                finishCallback();
            }
        );
    },

    /*
     * Draw a set of features on the canvas.
     * @private
     */
    _drawFeatures: function( scale, leftBase, rightBase, block, canvas, features, featureRects, dataScale ) {
        var context = canvas.getContext('2d');
        var canvasHeight = canvas.height;
        var toY = dojo.hitch( this, function( val ) {
           return canvasHeight * ( 1-dataScale.normalize.call(this, val) );
        });
        var originY = toY( dataScale.origin );

        var barColor  = {'matchCoverage':'#999', 'A':'#00BF00', 'T':'red', 'C':'#4747ff', 'G':'#d5bb04'}; // base colors from "main.css"
        var negColor  = this.config.style.neg_color;
        var clipColor = this.config.style.clip_marker_color;
        var bgColor   = this.config.style.bg_color;
        var disableClipMarkers = this.config.disable_clip_markers;

        var drawRectangle = function(ID, yPos, height, fRect) {
            // draw the background color if we are configured to do so
            if( bgColor && yPos >= 0 ) {
                context.fillStyle = bgColor;
                context.fillRect( fRect.l, 0, fRect.w, canvasHeight );
            }

            if( yPos <= canvasHeight ) { // if the rectangle is visible at all

                if( yPos <= originY ) {
                    // bar goes upward
                    context.fillStyle = barColor[ID] || 'black';
                    context.fillRect( fRect.l, yPos, fRect.w, height);
                    if( !disableClipMarkers && yPos < 0 ) { // draw clip marker if necessary
                        context.fillStyle = clipColor || negColor;
                        context.fillRect( fRect.l, 0, fRect.w, 2 );
                    }
                }
                else {
                    // bar goes downward (Should not be reached)

                    context.fillStyle = negColor;
                    context.fillRect( fRect.l, originY, fRect.w, height );
                    if( !disableClipMarkers && yPos >= canvasHeight ) { // draw clip marker if necessary
                        context.fillStyle = clipColor || barColor[ID];
                        context.fillRect( fRect.l, canvasHeight-3, fRect.w, 2 );
                    }
                }
            }
        };

        dojo.forEach( features, function(f,i) {
            var fRect = featureRects[i];
            var score = f.get('score');
            var totalHeight = 0;
            for (counts in score) {
                if (score.hasOwnProperty(counts)) {
                    totalHeight += score[counts];
                }
            }

            // Note: 'matchCoverage' is done first to ensure the grey part of the graph is on top
            drawRectangle('matchCoverage', toY(totalHeight), originY-toY( score['matchCoverage'] )+1, fRect);
            totalHeight -= score['matchCoverage'];

            for (counts in score) {
                if (score.hasOwnProperty(counts) && counts != 'matchCoverage') {
                    drawRectangle( counts, toY(totalHeight), originY-toY( score[counts] )+1, fRect);
                    totalHeight -= score[counts];
                }
            }

        }, this );
    },

    /**
     * parse a SAM MD tag to find mismatching bases of the template versus the reference
     * @returns {Array[Object]} array of mismatches and their positions
     */
    _mdToMismatches: function( feature, mdstring ) {
        var mismatchRecords = [];
        var curr = { start: 0, bases: '' };
        var seq = feature.get('seq');
        var nextRecord = function() {
              mismatchRecords.push( curr );
              curr = { start: curr.start + curr.bases.length, bases: ''};
        };
        array.forEach( mdstring.match(/(\d+|\^[a-z]+|[a-z])/ig), function( token ) {
          if( token.match(/^\d/) ) { // matching bases
              curr.start += parseInt( token );
          }
          else if( token.match(/^\^/) ) { // insertion in the template
              var i = token.length-1;
              while( i-- ) {
                  curr.bases = '*';
                  nextRecord();
              }
          }
          else if( token.match(/^[a-z]/i) ) { // mismatch
              curr.bases = seq.substr( curr.start, token.length );
              nextRecord();
          }
        });
        return mismatchRecords;
    },

    /*
     * The following method is required to override the equivalent method in "WiggleBase.js"
     * It displays more complete data.
     */
    _showPixelValue: function( scoreDisplay, score ) {
        if( typeof score['matchCoverage'] == 'number' ) {
            var scoreSummary = "COVERAGE SUMMARY
Matching Bases: "+score['matchCoverage']+'
';
            for (ID in score) {
                if (score.hasOwnProperty(ID) && ID != 'matchCoverage') {
                    scoreSummary += ID + ': ' +score[ID] +'
';
                }
            }
            scoreDisplay.innerHTML = scoreSummary;
            return true;
        } else {
            return false;
        }
    }
});
});<commit_msg>Edited coverage summary to handle cases where there is no matched coverage<commit_after>define( ['dojo/_base/declare',
         'dojo/_base/array',
         'JBrowse/View/Track/Wiggle',
         'JBrowse/Util'
        ],
        function( declare, array, Wiggle, Util ) {

// feature class for the features we make for the calculated coverage
// values
var CoverageFeature = Util.fastDeclare(
    {
        get: function(f) { return this[f]; },
        tags: function() { return [ 'start', 'end', 'score' ]; },
        score: 0,
        constructor: function( args ) {
            this.start = args.start;
            this.end = args.end;
            this.score = args.score;
        }
    });

return declare( Wiggle,
{

    _defaultConfig: function() {
        return Util.deepUpdate(
            dojo.clone( this.inherited(arguments) ),
            {
                min_score: 0,
                max_score: 100
            }
        );
    },

    getGlobalStats: function() {
        return {};
    },

    getFeatures: function( query, featureCallback, finishCallback, errorCallback ) {
        var leftBase  = query.start;
        var rightBase = query.end;
        var scale = query.scale; // px/bp
        var widthBp = rightBase-leftBase;
        var widthPx = widthBp * ( query.scale || 1/query.basesPerSpan);

        var binWidth = Math.ceil( query.basesPerSpan ); // in bp

        var coverageBins = {};
        var bpToBin = function( bp ) {
            return Math.floor( (bp-leftBase) / binWidth );
        };

        this.store.getFeatures(
            query,
            dojo.hitch( this, function( feature ) {
                            var startBin = bpToBin( feature.get('start') );
                            var endBin   = bpToBin( feature.get('end')-1 );
                            for( var i = startBin; i <= endBin; i++ ) {
                                if ( coverageBins[i] ) {
                                    coverageBins[i]['matchCoverage']++;
                                }
                                else {
                                    coverageBins[i] = {};
                                    coverageBins[i]['matchCoverage'] = 1;
                                }
                            }
                            // Calculate SNP coverage
                            var mdTag = feature.get('MD');
                            if(mdTag) {
                                var SNPs = this._mdToMismatches(feature, mdTag);
                                // loops through mismatches and updates coverage variables accordingly.
                                for (var i = 0; i<SNPs.length; i++) {
                                    var pos = bpToBin( feature.get('start') + SNPs[i].start );
                                    // Note: we reduce matchCoverage so the sum is the total coverage
                                    coverageBins[pos]['matchCoverage']--;
                                    if ( coverageBins[pos][SNPs[i].bases] ) {
                                        coverageBins[pos][SNPs[i].bases]++;
                                    }
                                    else {
                                        coverageBins[pos][SNPs[i].bases] = 1;
                                    }
                                }
                            }
                        }),
            function () {
                // make fake features from the coverage
                for( var i = 0; i < Math.ceil( widthBp/binWidth ); i++ ) {
                    var bpOffset = leftBase+binWidth*i;
                    featureCallback( new CoverageFeature({
                        start: bpOffset,
                        end:   bpOffset+binWidth,
                        score: coverageBins[i] || {'matchCoverage': 0}
                     }));
                }
                finishCallback();
            }
        );
    },

    /*
     * Draw a set of features on the canvas.
     * @private
     */
    _drawFeatures: function( scale, leftBase, rightBase, block, canvas, features, featureRects, dataScale ) {
        var context = canvas.getContext('2d');
        var canvasHeight = canvas.height;
        var toY = dojo.hitch( this, function( val ) {
           return canvasHeight * ( 1-dataScale.normalize.call(this, val) );
        });
        var originY = toY( dataScale.origin );

        var barColor  = {'matchCoverage':'#999', 'A':'#00BF00', 'T':'red', 'C':'#4747ff', 'G':'#d5bb04'}; // base colors from "main.css"
        var negColor  = this.config.style.neg_color;
        var clipColor = this.config.style.clip_marker_color;
        var bgColor   = this.config.style.bg_color;
        var disableClipMarkers = this.config.disable_clip_markers;

        var drawRectangle = function(ID, yPos, height, fRect) {
            // draw the background color if we are configured to do so
            if( bgColor && yPos >= 0 ) {
                context.fillStyle = bgColor;
                context.fillRect( fRect.l, 0, fRect.w, canvasHeight );
            }

            if( yPos <= canvasHeight ) { // if the rectangle is visible at all

                if( yPos <= originY ) {
                    // bar goes upward
                    context.fillStyle = barColor[ID] || 'black';
                    context.fillRect( fRect.l, yPos, fRect.w, height);
                    if( !disableClipMarkers && yPos < 0 ) { // draw clip marker if necessary
                        context.fillStyle = clipColor || negColor;
                        context.fillRect( fRect.l, 0, fRect.w, 2 );
                    }
                }
                else {
                    // bar goes downward (Should not be reached)

                    context.fillStyle = negColor;
                    context.fillRect( fRect.l, originY, fRect.w, height );
                    if( !disableClipMarkers && yPos >= canvasHeight ) { // draw clip marker if necessary
                        context.fillStyle = clipColor || barColor[ID];
                        context.fillRect( fRect.l, canvasHeight-3, fRect.w, 2 );
                    }
                }
            }
        };

        dojo.forEach( features, function(f,i) {
            var fRect = featureRects[i];
            var score = f.get('score');
            var totalHeight = 0;
            for (counts in score) {
                if (score.hasOwnProperty(counts)) {
                    totalHeight += score[counts];
                }
            }

            // Note: 'matchCoverage' is done first to ensure the grey part of the graph is on top
            drawRectangle('matchCoverage', toY(totalHeight), originY-toY( score['matchCoverage'] )+1, fRect);
            totalHeight -= score['matchCoverage'];

            for (counts in score) {
                if (score.hasOwnProperty(counts) && counts != 'matchCoverage') {
                    drawRectangle( counts, toY(totalHeight), originY-toY( score[counts] )+1, fRect);
                    totalHeight -= score[counts];
                }
            }

        }, this );
    },

    /**
     * parse a SAM MD tag to find mismatching bases of the template versus the reference
     * @returns {Array[Object]} array of mismatches and their positions
     */
    _mdToMismatches: function( feature, mdstring ) {
        var mismatchRecords = [];
        var curr = { start: 0, bases: '' };
        var seq = feature.get('seq');
        var nextRecord = function() {
              mismatchRecords.push( curr );
              curr = { start: curr.start + curr.bases.length, bases: ''};
        };
        array.forEach( mdstring.match(/(\d+|\^[a-z]+|[a-z])/ig), function( token ) {
          if( token.match(/^\d/) ) { // matching bases
              curr.start += parseInt( token );
          }
          else if( token.match(/^\^/) ) { // insertion in the template
              var i = token.length-1;
              while( i-- ) {
                  curr.bases = '*';
                  nextRecord();
              }
          }
          else if( token.match(/^[a-z]/i) ) { // mismatch
              curr.bases = seq.substr( curr.start, token.length );
              nextRecord();
          }
        });
        return mismatchRecords;
    },

    /*
     * The following method is required to override the equivalent method in "WiggleBase.js"
     * It displays more complete data.
     */
    _showPixelValue: function( scoreDisplay, score ) {
        if( typeof score['matchCoverage'] == 'number') {
            var scoreSummary = "COVERAGE SUMMARY
";
            if (score['matchCoverage']){scoreSummary += "Matching Bases: "+score['matchCoverage']+'
';}
            for (ID in score) {
                if (score.hasOwnProperty(ID) && ID != 'matchCoverage') {
                    scoreSummary += ID + ': ' +score[ID] +'
';
                }
            }
            scoreDisplay.innerHTML = scoreSummary;
            return true;
        } else {
            return false;
        }
    }
});
});<|endoftext|>


<commit_before>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

(function(document) {
  'use strict';

  function finishLazyLoading(){
    // Grab a reference to our auto-binding template
    // and give it some initial binding values
    // Learn more about auto-binding templates at http://goo.gl/Dx1u2g
    var app = document.querySelector('#app');

    //set default host;
    app.host = 'dev.bridgeit.io';

    app.displayInstalledToast = function() {
      // Check to make sure caching is actually enabled—it won't be in the dev environment.
      if (!document.querySelector('platinum-sw-cache').disabled) {
        document.querySelector('#caching-complete').show();
      }
    };

    // Listen for template bound event to know when bindings
    // have resolved and content has been stamped to the page
    app.addEventListener('dom-change', function() {
      console.log('Initializing demo');
      if( bridgeit.io.auth.isLoggedIn()){
        setTimeout(function(){
          setupNotificationListener();
          //initialize lastNotificationTimestamp so user list displays
          var demoData = app.$.demoView.$$('#demoData');
          if( demoData ){
             demoData.lastNotificationTimestamp = new Date().getTime();
          }
        }, 5000);
      }
    });

    // Startup the Notification Push Listener after login
    window.addEventListener('onAfterLogin', function(){
      console.log('onAfterLogin callback: configuring notifications');
      setupNotificationListener();
    });

    function setupNotificationListener(){
      bridgeit.xio.push.attach('http://dev.bridgeit.io/pushio/demos/realms/freight', bridgeit.io.auth.getLastKnownUsername());
      bridgeit.xio.push.addListener(function (payload) {
          console.log('Notification: ', payload);

          //normalize payload TODO!!
          if( payload.message && typeof payload.message === 'object' && payload.message.message){
            payload.message = payload.message.message;
          }

          //ignore first batch of notifications for admin as they are irrelevant
          payload.usernameFromGroup = payload.group.split('/').pop();
          if( payload.message === 'joined' && payload.username !== payload.usernameFromGroup ){
            console.log('suppressing notification display');
            return;
          }

          var messageToDisplay;
          if( payload.message === 'joined' ){
            messageToDisplay = payload.usernameFromGroup + ' joined';
          }
          else{
            messageToDisplay = payload.message;
          }

          var demoView = app.$.demoView;
          demoView.$$('demo-data').push('notifications', payload);

          demoView.message = messageToDisplay;
          demoView.querySelector('#toast').show();

          var demoData = demoView.$$('#demoData');
          if( demoData ){
            if( !demoData.notificationsByUser ){
              demoData.notificationsByUser = {};
            }
            var userNotificationList = demoData.notificationsByUser[payload.usernameFromGroup];
            if( !userNotificationList ){
              userNotificationList = demoData.notificationsByUser[payload.usernameFromGroup] = [];
            }
            userNotificationList.push(payload);
            demoData.lastNotificationTimestamp = payload.time;
          }
          else{
            console.warn('could not locate demoData element to store user notification');
          }
      });
      window.initializePushGroups(); //delegates to index.html for admins or client.html for regular users
    }

    // See https://github.com/Polymer/polymer/issues/1381
    window.addEventListener('WebComponentsReady', function() {
      // imports are loaded and elements have been registered
    });

    window.addEventListener('bridgeit-access-token-refreshed', function(e){
      console.log('demo app received event bridgeit-access-token-refreshed', e);
      bridgeit.xio.push.refreshConnection();
    });

    window.addEventListener('bridgeit-session-expired', function(e){
      console.log('demo app received event bridgeit-session-expired', e);
      bridgeit.xio.push.disconnect();
    });

    // Main area's paper-scroll-header-panel custom condensing transformation of
    // the appName in the middle-container and the bottom title in the bottom-container.
    // The appName is moved to top and shrunk on condensing. The bottom sub title
    // is shrunk to nothing on condensing.
    addEventListener('paper-header-transform', function(e) {
      var appName = document.querySelector('#mainToolbar .app-name');
      var middleContainer = document.querySelector('#mainToolbar .middle-container');
      var bottomContainer = document.querySelector('#mainToolbar .bottom-container');
      var detail = e.detail;
      var heightDiff = detail.height - detail.condensedHeight;
      var yRatio = Math.min(1, detail.y / heightDiff);
      var maxMiddleScale = 0.50;  // appName max size when condensed. The smaller the number the smaller the condensed size.
      var scaleMiddle = Math.max(maxMiddleScale, (heightDiff - detail.y) / (heightDiff / (1-maxMiddleScale))  + maxMiddleScale);
      var scaleBottom = 1 - yRatio;

      // Move/translate middleContainer
      Polymer.Base.transform('translate3d(0,' + yRatio * 100 + '%,0)', middleContainer);

      // Scale bottomContainer and bottom sub title to nothing and back
      Polymer.Base.transform('scale(' + scaleBottom + ') translateZ(0)', bottomContainer);

      // Scale middleContainer appName
      Polymer.Base.transform('scale(' + scaleMiddle + ') translateZ(0)', appName);
    });

    // Close drawer after menu item is selected if drawerPanel is narrow
    app.onDataRouteClick = function() {
      var drawerPanel = document.getElementById('paperDrawerPanel');
      if (drawerPanel.narrow) {
        drawerPanel.closeDrawer();
      }
    };

    // Scroll page to top and expand header
    app.scrollPageToTop = function() {
      document.getElementById('mainContainer').scrollTop = 0;
    };
  }

  var webComponentsSupported = (
    'registerElement' in document &&
    'import' in document.createElement('link') &&
    'content' in document.createElement('template'));

  if( !webComponentsSupported ){
    var script = document.createElement('script');
    script.async = true;
    script.src = 'bower_components/webcomponentsjs/webcomponents-lite.min.js';
    script.onload = finishLazyLoading;
    document.head.appendChild(script);
  }
  else{
    finishLazyLoading();
  }

})(document);
<commit_msg>Use specified hostname for push as well.<commit_after>/*
Copyright (c) 2015 The Polymer Project Authors. All rights reserved.
This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
Code distributed by Google as part of the polymer project is also
subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
*/

(function(document) {
  'use strict';

  function finishLazyLoading(){
    // Grab a reference to our auto-binding template
    // and give it some initial binding values
    // Learn more about auto-binding templates at http://goo.gl/Dx1u2g
    var app = document.querySelector('#app');

    //set default host;
    app.host = 'dev.bridgeit.io';

    app.displayInstalledToast = function() {
      // Check to make sure caching is actually enabled—it won't be in the dev environment.
      if (!document.querySelector('platinum-sw-cache').disabled) {
        document.querySelector('#caching-complete').show();
      }
    };

    // Listen for template bound event to know when bindings
    // have resolved and content has been stamped to the page
    app.addEventListener('dom-change', function() {
      console.log('Initializing demo');
      if( bridgeit.io.auth.isLoggedIn()){
        setTimeout(function(){
          setupNotificationListener();
          //initialize lastNotificationTimestamp so user list displays
          var demoData = app.$.demoView.$$('#demoData');
          if( demoData ){
             demoData.lastNotificationTimestamp = new Date().getTime();
          }
        }, 5000);
      }
    });

    // Startup the Notification Push Listener after login
    window.addEventListener('onAfterLogin', function(){
      console.log('onAfterLogin callback: configuring notifications');
      setupNotificationListener();
    });

    function setupNotificationListener(){
      bridgeit.xio.push.attach('http://'+app.host+'/pushio/demos/realms/freight', bridgeit.io.auth.getLastKnownUsername());
      bridgeit.xio.push.addListener(function (payload) {
          console.log('Notification: ', payload);

          //normalize payload TODO!!
          if( payload.message && typeof payload.message === 'object' && payload.message.message){
            payload.message = payload.message.message;
          }

          //ignore first batch of notifications for admin as they are irrelevant
          payload.usernameFromGroup = payload.group.split('/').pop();
          if( payload.message === 'joined' && payload.username !== payload.usernameFromGroup ){
            console.log('suppressing notification display');
            return;
          }

          var messageToDisplay;
          if( payload.message === 'joined' ){
            messageToDisplay = payload.usernameFromGroup + ' joined';
          }
          else{
            messageToDisplay = payload.message;
          }

          var demoView = app.$.demoView;
          demoView.$$('demo-data').push('notifications', payload);

          demoView.message = messageToDisplay;
          demoView.querySelector('#toast').show();

          var demoData = demoView.$$('#demoData');
          if( demoData ){
            if( !demoData.notificationsByUser ){
              demoData.notificationsByUser = {};
            }
            var userNotificationList = demoData.notificationsByUser[payload.usernameFromGroup];
            if( !userNotificationList ){
              userNotificationList = demoData.notificationsByUser[payload.usernameFromGroup] = [];
            }
            userNotificationList.push(payload);
            demoData.lastNotificationTimestamp = payload.time;
          }
          else{
            console.warn('could not locate demoData element to store user notification');
          }
      });
      window.initializePushGroups(); //delegates to index.html for admins or client.html for regular users
    }

    // See https://github.com/Polymer/polymer/issues/1381
    window.addEventListener('WebComponentsReady', function() {
      // imports are loaded and elements have been registered
    });

    window.addEventListener('bridgeit-access-token-refreshed', function(e){
      console.log('demo app received event bridgeit-access-token-refreshed', e);
      bridgeit.xio.push.refreshConnection();
    });

    window.addEventListener('bridgeit-session-expired', function(e){
      console.log('demo app received event bridgeit-session-expired', e);
      bridgeit.xio.push.disconnect();
    });

    // Main area's paper-scroll-header-panel custom condensing transformation of
    // the appName in the middle-container and the bottom title in the bottom-container.
    // The appName is moved to top and shrunk on condensing. The bottom sub title
    // is shrunk to nothing on condensing.
    addEventListener('paper-header-transform', function(e) {
      var appName = document.querySelector('#mainToolbar .app-name');
      var middleContainer = document.querySelector('#mainToolbar .middle-container');
      var bottomContainer = document.querySelector('#mainToolbar .bottom-container');
      var detail = e.detail;
      var heightDiff = detail.height - detail.condensedHeight;
      var yRatio = Math.min(1, detail.y / heightDiff);
      var maxMiddleScale = 0.50;  // appName max size when condensed. The smaller the number the smaller the condensed size.
      var scaleMiddle = Math.max(maxMiddleScale, (heightDiff - detail.y) / (heightDiff / (1-maxMiddleScale))  + maxMiddleScale);
      var scaleBottom = 1 - yRatio;

      // Move/translate middleContainer
      Polymer.Base.transform('translate3d(0,' + yRatio * 100 + '%,0)', middleContainer);

      // Scale bottomContainer and bottom sub title to nothing and back
      Polymer.Base.transform('scale(' + scaleBottom + ') translateZ(0)', bottomContainer);

      // Scale middleContainer appName
      Polymer.Base.transform('scale(' + scaleMiddle + ') translateZ(0)', appName);
    });

    // Close drawer after menu item is selected if drawerPanel is narrow
    app.onDataRouteClick = function() {
      var drawerPanel = document.getElementById('paperDrawerPanel');
      if (drawerPanel.narrow) {
        drawerPanel.closeDrawer();
      }
    };

    // Scroll page to top and expand header
    app.scrollPageToTop = function() {
      document.getElementById('mainContainer').scrollTop = 0;
    };
  }

  var webComponentsSupported = (
    'registerElement' in document &&
    'import' in document.createElement('link') &&
    'content' in document.createElement('template'));

  if( !webComponentsSupported ){
    var script = document.createElement('script');
    script.async = true;
    script.src = 'bower_components/webcomponentsjs/webcomponents-lite.min.js';
    script.onload = finishLazyLoading;
    document.head.appendChild(script);
  }
  else{
    finishLazyLoading();
  }

})(document);
<|endoftext|>


<commit_before>import Ember from 'ember';
/*global Em*/
/* global $ */

export default Ember.Component.extend({

    tagName: "div",

    classNames: ["cell"],

    cell: null,

    backupValue: null,

    didInsertElement() {
        this.layout();
        this.$().attr("tabindex", 1);

        this.$().on("keydown", (e) => {

            if (e.keyCode === 9) { //tab
                this.cycleSelection(e.shiftKey ? -1:1);
                e.preventDefault();
            }

            if (!this.get('cell.state.sheet.edited')) {
                switch (e.keyCode) {
                    case 37:
                        this.moveSelection(0,-1);
                        e.preventDefault();
                        break;
                    case 38:
                        this.moveSelection(-1,0);
                        e.preventDefault();
                        break;
                    case 39:
                        this.moveSelection(0,1);
                        e.preventDefault();
                        break;
                    case 40:
                        this.moveSelection(1,0);
                        e.preventDefault();
                        break;
                }
            }

        });

        this.$().on("keyup", (e) => {
            if (e.keyCode === 13) { //enter
                this.startEdition();
            } else if (e.keyCode === 8) { //backspace
                this.startEdition();
                this.set('cell.value', "");
            } else if (e.keyCode === 27) { //esc
                if (!this.get('cell.state.sheet.edited')) {
                    this.endSelection();
                }
            }
            if (!this.get('cell.state.sheet.edited')) {
                e.stopImmediatePropagation();
            }
        });

    },

    toggleEditedState: function() {
        this.$().toggleClass('edited', this.get('cell.state.sheet.edited'));

        if (this.get('cell.state.sheet.edited')) {
            this.set('backupValue', this.get('cell.value'));
            this.$('input').focus().select();
        }
    }.observes('cell.state.sheet.edited'),

    toggleSelectedState: function() {
        if (!this.$().hasClass('selected') && this.get('cell.state.sheet.selected')) {
            this.$().focus();
        } else if (this.$().hasClass('selected') && !this.get('cell.state.sheet.selected')) {
            this.$().blur();
        }
        this.$().toggleClass('selected', this.get('cell.state.sheet.selected'));
    }.observes('cell.state.sheet.selected'),

    toggleResizingState: function() {
        this.$().toggleClass('resizing', this.get('cell.state.sheet.resizing'));
    }.observes('cell.state.sheet.resizing'),

    click(e) {
        this.startSelection();
        e.stopImmediatePropagation();
    },

    doubleClick(e) {
        this.get('cell.state.sheet.edited') ? this.commitEdition() : this.startEdition();
        e.stopImmediatePropagation();
    },

    layout: function() {
        if (this.get('cell.column.layout.sheet.width')) {
            this.$().outerWidth(this.get('cell.column.layout.sheet.width'));
        }
        if (this.get('cell.column.layout.sheet.height')) {
            this.$().outerHeight(this.get('cell.row.layout.sheet.height'));
        }
    }.observes('cell.column.layout.sheet.width', 'cell.row.layout.sheet.height'),

    startSelection() {
        this.sendAction('select-start', this.get('cell'), this);
    },

    endSelection() {
        this.sendAction('select-end', this.get('cell'), this);
    },

    moveSelection(row, col) {
        this.sendAction('move-selection', this.get('cell'), row, col, this);
    },

    cycleSelection(shift) {
        this.sendAction('cycle-selection', this.get('cell'), shift, this);
    },

    startEdition() {
        this.sendAction('edit-start', this.get('cell'), this);
        this.sendAction('select-start', this.get('cell'), this);
    },

    cancelEdition() {
        this.set('cell.value', this.get('backupValue'));
        this.sendAction('edit-end', this.get('cell'), this);
        this.$().focus();
    },

    commitEdition() {
        this.sendAction('edit-end', this.get('cell'), this);
        this.$().focus();
    },

    actions: {

        onInputEnter() {
            this.commitEdition();
        },

        onInputBlur() {
            if (this.get('cell.state.sheet.edited')) {
                this.sendAction('edit-end', this.get('cell'), this);
            }
        },

        onKeyUp(v, e) {
            if (e.keyCode === 27) {//esc
                this.cancelEdition();
            }
        }

    }

});<commit_msg>Edition par backspace<commit_after>import Ember from 'ember';
/*global Em*/
/* global $ */

export default Ember.Component.extend({

    tagName: "div",

    classNames: ["cell"],

    cell: null,

    backupValue: null,

    didInsertElement() {
        this.layout();
        this.$().attr("tabindex", 1);

        this.$().on("keydown", (e) => {

            if (e.keyCode === 9) { //tab
                this.cycleSelection(e.shiftKey ? -1:1);
                e.preventDefault();
            }

            if (e.keyCode === 8) { //backspace
                e.preventDefault();
            }

            if (!this.get('cell.state.sheet.edited')) {
                switch (e.keyCode) {
                    case 37:
                        this.moveSelection(0,-1);
                        e.preventDefault();
                        break;
                    case 38:
                        this.moveSelection(-1,0);
                        e.preventDefault();
                        break;
                    case 39:
                        this.moveSelection(0,1);
                        e.preventDefault();
                        break;
                    case 40:
                        this.moveSelection(1,0);
                        e.preventDefault();
                        break;
                }
            }

        });

        this.$().on("keyup", (e) => {
            if (e.keyCode === 13) { //enter
                this.startEdition();
            } else if (e.keyCode === 8) { //backspace
                e.preventDefault();
                this.startEdition();
                this.set('cell.value', "");
            } else if (e.keyCode === 27) { //esc
                if (!this.get('cell.state.sheet.edited')) {
                    this.endSelection();
                }
            }
            if (!this.get('cell.state.sheet.edited')) {
                e.stopImmediatePropagation();
            }
        });

    },

    toggleEditedState: function() {
        this.$().toggleClass('edited', this.get('cell.state.sheet.edited'));

        if (this.get('cell.state.sheet.edited')) {
            this.set('backupValue', this.get('cell.value'));
            this.$('input').focus().select();
        }
    }.observes('cell.state.sheet.edited'),

    toggleSelectedState: function() {
        if (!this.$().hasClass('selected') && this.get('cell.state.sheet.selected')) {
            this.$().focus();
        } else if (this.$().hasClass('selected') && !this.get('cell.state.sheet.selected')) {
            this.$().blur();
        }
        this.$().toggleClass('selected', this.get('cell.state.sheet.selected'));
    }.observes('cell.state.sheet.selected'),

    toggleResizingState: function() {
        this.$().toggleClass('resizing', this.get('cell.state.sheet.resizing'));
    }.observes('cell.state.sheet.resizing'),

    click(e) {
        this.startSelection();
        e.stopImmediatePropagation();
    },

    doubleClick(e) {
        this.get('cell.state.sheet.edited') ? this.commitEdition() : this.startEdition();
        e.stopImmediatePropagation();
    },

    layout: function() {
        if (this.get('cell.column.layout.sheet.width')) {
            this.$().outerWidth(this.get('cell.column.layout.sheet.width'));
        }
        if (this.get('cell.column.layout.sheet.height')) {
            this.$().outerHeight(this.get('cell.row.layout.sheet.height'));
        }
    }.observes('cell.column.layout.sheet.width', 'cell.row.layout.sheet.height'),

    startSelection() {
        this.sendAction('select-start', this.get('cell'), this);
    },

    endSelection() {
        this.sendAction('select-end', this.get('cell'), this);
    },

    moveSelection(row, col) {
        this.sendAction('move-selection', this.get('cell'), row, col, this);
    },

    cycleSelection(shift) {
        this.sendAction('cycle-selection', this.get('cell'), shift, this);
    },

    startEdition() {
        this.sendAction('edit-start', this.get('cell'), this);
        this.sendAction('select-start', this.get('cell'), this);
    },

    cancelEdition() {
        this.set('cell.value', this.get('backupValue'));
        this.sendAction('edit-end', this.get('cell'), this);
        this.$().focus();
    },

    commitEdition() {
        this.sendAction('edit-end', this.get('cell'), this);
        this.$().focus();
    },

    actions: {

        onInputEnter() {
            this.commitEdition();
        },

        onInputBlur() {
            if (this.get('cell.state.sheet.edited')) {
                this.sendAction('edit-end', this.get('cell'), this);
            }
        },

        onKeyUp(v, e) {
            if (e.keyCode === 27) {//esc
                this.cancelEdition();
            }
        }

    }

});<|endoftext|>