<commit_before>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Variable input field.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.FieldVariable');

goog.require('Blockly.FieldDropdown');
goog.require('Blockly.Msg');
goog.require('Blockly.VariableModel');
goog.require('Blockly.Variables');
goog.require('goog.asserts');
goog.require('goog.string');

/**
 * Class for a variable's dropdown field.
 * @param {?string} varname The default name for the variable.  If null,
 *     a unique variable name will be generated.
 * @param {Function=} opt_validator A function that is executed when a new
 *     option is selected.  Its sole argument is the new option value.
 * @param {Array.<string>} opt_variableTypes A list of the types of variables to
 *     include in the dropdown.
 * @extends {Blockly.FieldDropdown}
 * @constructor
 */
Blockly.FieldVariable = function(varname, opt_validator, opt_variableTypes) {
  Blockly.FieldVariable.superClass_.constructor.call(this,
      Blockly.FieldVariable.dropdownCreate, opt_validator);
  this.setValue(varname || '');
  this.addArgType('variable');
  this.variableTypes = opt_variableTypes;
  this.variableType = (opt_variableTypes && opt_variableTypes.length == 1) ?
    opt_variableTypes[0] : '';
};
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);

/**
 * Install this dropdown on a block.
 */
Blockly.FieldVariable.prototype.init = function() {
  if (this.fieldGroup_) {
    // Dropdown has already been initialized once.
    return;
  }
  Blockly.FieldVariable.superClass_.init.call(this);

  // TODO (1010): Change from init/initModel to initView/initModel
  this.initModel();
};

Blockly.FieldVariable.prototype.initModel = function() {
  if (!this.getValue()) {
    // Variables without names get uniquely named for this workspace.
    var workspace =
        this.sourceBlock_.isInFlyout ?
            this.sourceBlock_.workspace.targetWorkspace :
            this.sourceBlock_.workspace;
    this.setValue(Blockly.Variables.generateUniqueName(workspace));
  }
  // If the selected variable doesn't exist yet, create it.
  // For instance, some blocks in the toolbox have variable dropdowns filled
  // in by default.
  if (!this.sourceBlock_.isInFlyout) {
    // Check if there was exactly one element specified in the
    // variableTypes list. This is the list that specifies which types of
    // variables to include in the dropdown.
    this.sourceBlock_.workspace.createVariable(this.getValue(), this.variableType);
  } else {
    // Using shorter name for this constant
    var broadcastMsgType = Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE;
    var broadcastVars = this.sourceBlock_.workspace.getVariablesOfType(broadcastMsgType);
    if (this.variableType == broadcastMsgType && broadcastVars.length != 0) {
      broadcastVars.sort(Blockly.VariableModel.compareByName);
      this.setValue(broadcastVars[0].name);
    }
  }
};

/**
 * Attach this field to a block.
 * @param {!Blockly.Block} block The block containing this field.
 */
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
  goog.asserts.assert(!block.isShadow(),
      'Variable fields are not allowed to exist on shadow blocks.');
  Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
};

/**
 * Get the variable's name (use a variableDB to convert into a real name).
 * Unline a regular dropdown, variables are literal and have no neutral value.
 * @return {string} Current text.
 */
Blockly.FieldVariable.prototype.getValue = function() {
  return this.getText();
};

/**
 * Set the variable name.
 * @param {string} value New text.
 */
Blockly.FieldVariable.prototype.setValue = function(value) {
  var newValue = value;
  var newText = value;

  if (this.sourceBlock_) {
    var variable = this.sourceBlock_.workspace.getVariableById(value);
    if (variable) {
      newText = variable.name;
    }
    // TODO(marisaleung): Remove name lookup after converting all Field Variable
    //     instances to use id instead of name.
    else if (variable = this.sourceBlock_.workspace.getVariable(value)) {
      newValue = variable.getId();
    }
    if (Blockly.Events.isEnabled()) {
      Blockly.Events.fire(new Blockly.Events.BlockChange(
          this.sourceBlock_, 'field', this.name, this.value_, newValue));
    }
  }
  this.value_ = newValue;
  this.setText(newText);
};

/**
 * Return a list of variable types to include in the dropdown.
 * @return {!Array.<string>} Array of variable types.
 * @throws {Error} if variableTypes is an empty array.
 * @private
 */
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
  var variableTypes = this.variableTypes;
  if (variableTypes === null) {
    // If variableTypes is null, return all variable types.
    if (this.sourceBlock_) {
      var workspace = this.sourceBlock_.workspace;
      return workspace.getVariableTypes();
    }
  }
  variableTypes = variableTypes || [''];
  if (variableTypes.length == 0) {
    // Throw an error if variableTypes is an empty list.
    var name = this.getText();
    throw new Error('\'variableTypes\' of field variable ' +
      name + ' was an empty list');
  }
  return variableTypes;
};

/**
 * Return a sorted list of variable names for variable dropdown menus.
 * Include a special option at the end for creating a new variable name.
 * @return {!Array.<string>} Array of variable names.
 * @this {Blockly.FieldVariable}
 */
Blockly.FieldVariable.dropdownCreate = function() {
  var variableModelList = [];
  var name = this.getText();
  // Don't create a new variable if there is nothing selected.
  var createSelectedVariable = name ? true : false;
  var workspace = null;
  if (this.sourceBlock_) {
    workspace = this.sourceBlock_.workspace;
  }
  var isBroadcastType = false;
  if (workspace) {
    var variableTypes = this.getVariableTypes_();
    var variableModelList = [];
    // Get a copy of the list, so that adding rename and new variable options
    // doesn't modify the workspace's list.
    for (var i = 0; i < variableTypes.length; i++) {
      var variableType = variableTypes[i];
      if (variableType == Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE){
        isBroadcastType = true;
      }
      var variables = workspace.getVariablesOfType(variableType);
      variableModelList = variableModelList.concat(variables);
    }
    for (var i = 0; i < variableModelList.length; i++){
      if (createSelectedVariable &&
          goog.string.caseInsensitiveEquals(variableModelList[i].name, name)) {
        createSelectedVariable = false;
        break;
      }
    }
  }
  // Ensure that the currently selected variable is an option.
  if (createSelectedVariable && workspace) {
    var newVar = null;
    if (isBroadcastType && workspace.isFlyout) {
      newVar = workspace.targetWorkspace.createVariable(name, Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE);
    } else {
      newVar = workspace.createVariable(name);
    }
    variableModelList.push(newVar);
  }
  variableModelList.sort(Blockly.VariableModel.compareByName);
  var options = [];
  for (var i = 0; i < variableModelList.length; i++) {
    // Set the uuid as the internal representation of the variable.
    options[i] = [variableModelList[i].name, variableModelList[i].getId()];
  }
  if (isBroadcastType) {
    options.push([Blockly.Msg.NEW_BROADCAST_MESSAGE, Blockly.NEW_BROADCAST_MESSAGE_ID]);
  } else {
    options.push([Blockly.Msg.RENAME_VARIABLE, Blockly.RENAME_VARIABLE_ID]);
    if (Blockly.Msg.DELETE_VARIABLE) {
      options.push([Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
          Blockly.DELETE_VARIABLE_ID]);
    }
  }
  return options;
};

/**
 * Handle the selection of an item in the variable dropdown menu.
 * Special case the 'Rename variable...' and 'Delete variable...' options.
 * In the rename case, prompt the user for a new name.
 * @param {!goog.ui.Menu} menu The Menu component clicked.
 * @param {!goog.ui.MenuItem} menuItem The MenuItem selected within menu.
 */
Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
  var id = menuItem.getValue();
  // TODO(marisaleung): change setValue() to take in an id as the parameter.
  // Then remove itemText.
  var itemText;
  if (this.sourceBlock_ && this.sourceBlock_.workspace) {
    var workspace = this.sourceBlock_.workspace;
    var variable = workspace.getVariableById(id);
    // If the item selected is a variable, set itemText to the variable name.
    if (variable) {
      itemText = variable.name;
    }
    else if (id == Blockly.RENAME_VARIABLE_ID) {
      // Rename variable.
      var currentName = this.getText();
      variable = workspace.getVariable(currentName);
      Blockly.Variables.renameVariable(workspace, variable);
      return;
    } else if (id == Blockly.DELETE_VARIABLE_ID) {
      // Delete variable.
      workspace.deleteVariable(this.getText());
      return;
    } else if (id == Blockly.NEW_BROADCAST_MESSAGE_ID) {
      var thisField = this;
      var setName = function(newName) {
        if (newName) {
          thisField.setValue(newName);
        }
      };
      var broadcastMsgWkspc = workspace.isFlyout ? workspace.targetWorkspace : workspace;
      Blockly.Variables.createVariable(broadcastMsgWkspc, setName, Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE);
      return;
    }

    // Call any validation function, and allow it to override.
    itemText = this.callValidator(itemText);
  }
  if (itemText !== null) {
    this.setValue(itemText);
  }
};
<commit_msg>Some code cleanup.<commit_after>/**
 * @license
 * Visual Blocks Editor
 *
 * Copyright 2012 Google Inc.
 * https://developers.google.com/blockly/
 *
 * 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.
 */

/**
 * @fileoverview Variable input field.
 * @author fraser@google.com (Neil Fraser)
 */
'use strict';

goog.provide('Blockly.FieldVariable');

goog.require('Blockly.FieldDropdown');
goog.require('Blockly.Msg');
goog.require('Blockly.VariableModel');
goog.require('Blockly.Variables');
goog.require('goog.asserts');
goog.require('goog.string');

/**
 * Class for a variable's dropdown field.
 * @param {?string} varname The default name for the variable.  If null,
 *     a unique variable name will be generated.
 * @param {Function=} opt_validator A function that is executed when a new
 *     option is selected.  Its sole argument is the new option value.
 * @param {Array.<string>} opt_variableTypes A list of the types of variables to
 *     include in the dropdown.
 * @extends {Blockly.FieldDropdown}
 * @constructor
 */
Blockly.FieldVariable = function(varname, opt_validator, opt_variableTypes) {
  Blockly.FieldVariable.superClass_.constructor.call(this,
      Blockly.FieldVariable.dropdownCreate, opt_validator);
  this.setValue(varname || '');
  this.addArgType('variable');
  this.variableTypes = opt_variableTypes;
  this.variableType = (opt_variableTypes && opt_variableTypes.length == 1) ?
    opt_variableTypes[0] : '';
};
goog.inherits(Blockly.FieldVariable, Blockly.FieldDropdown);

/**
 * Install this dropdown on a block.
 */
Blockly.FieldVariable.prototype.init = function() {
  if (this.fieldGroup_) {
    // Dropdown has already been initialized once.
    return;
  }
  Blockly.FieldVariable.superClass_.init.call(this);

  // TODO (1010): Change from init/initModel to initView/initModel
  this.initModel();
};

Blockly.FieldVariable.prototype.initModel = function() {
  if (!this.getValue()) {
    // Variables without names get uniquely named for this workspace.
    var workspace =
        this.sourceBlock_.isInFlyout ?
            this.sourceBlock_.workspace.targetWorkspace :
            this.sourceBlock_.workspace;
    this.setValue(Blockly.Variables.generateUniqueName(workspace));
  }
  // If the selected variable doesn't exist yet, create it.
  // For instance, some blocks in the toolbox have variable dropdowns filled
  // in by default.
  if (!this.sourceBlock_.isInFlyout) {
    // Check if there was exactly one element specified in the
    // variableTypes list. This is the list that specifies which types of
    // variables to include in the dropdown.
    this.sourceBlock_.workspace.createVariable(this.getValue(), this.variableType);
  } else {
    // Using shorter name for this constant
    var broadcastMsgType = Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE;
    var broadcastVars = this.sourceBlock_.workspace.getVariablesOfType(broadcastMsgType);
    if (this.variableType == broadcastMsgType && broadcastVars.length != 0) {
      broadcastVars.sort(Blockly.VariableModel.compareByName);
      this.setValue(broadcastVars[0].name);
    }
  }
};

/**
 * Attach this field to a block.
 * @param {!Blockly.Block} block The block containing this field.
 */
Blockly.FieldVariable.prototype.setSourceBlock = function(block) {
  goog.asserts.assert(!block.isShadow(),
      'Variable fields are not allowed to exist on shadow blocks.');
  Blockly.FieldVariable.superClass_.setSourceBlock.call(this, block);
};

/**
 * Get the variable's name (use a variableDB to convert into a real name).
 * Unline a regular dropdown, variables are literal and have no neutral value.
 * @return {string} Current text.
 */
Blockly.FieldVariable.prototype.getValue = function() {
  return this.getText();
};

/**
 * Set the variable name.
 * @param {string} value New text.
 */
Blockly.FieldVariable.prototype.setValue = function(value) {
  var newValue = value;
  var newText = value;

  if (this.sourceBlock_) {
    var variable = this.sourceBlock_.workspace.getVariableById(value);
    if (variable) {
      newText = variable.name;
    }
    // TODO(marisaleung): Remove name lookup after converting all Field Variable
    //     instances to use id instead of name.
    else if (variable = this.sourceBlock_.workspace.getVariable(value)) {
      newValue = variable.getId();
    }
    if (Blockly.Events.isEnabled()) {
      Blockly.Events.fire(new Blockly.Events.BlockChange(
          this.sourceBlock_, 'field', this.name, this.value_, newValue));
    }
  }
  this.value_ = newValue;
  this.setText(newText);
};

/**
 * Return a list of variable types to include in the dropdown.
 * @return {!Array.<string>} Array of variable types.
 * @throws {Error} if variableTypes is an empty array.
 * @private
 */
Blockly.FieldVariable.prototype.getVariableTypes_ = function() {
  var variableTypes = this.variableTypes;
  if (variableTypes === null) {
    // If variableTypes is null, return all variable types.
    if (this.sourceBlock_) {
      var workspace = this.sourceBlock_.workspace;
      return workspace.getVariableTypes();
    }
  }
  variableTypes = variableTypes || [''];
  if (variableTypes.length == 0) {
    // Throw an error if variableTypes is an empty list.
    var name = this.getText();
    throw new Error('\'variableTypes\' of field variable ' +
      name + ' was an empty list');
  }
  return variableTypes;
};

/**
 * Return a sorted list of variable names for variable dropdown menus.
 * Include a special option at the end for creating a new variable name.
 * @return {!Array.<string>} Array of variable names.
 * @this {Blockly.FieldVariable}
 */
Blockly.FieldVariable.dropdownCreate = function() {
  var variableModelList = [];
  var name = this.getText();
  // Don't create a new variable if there is nothing selected.
  var createSelectedVariable = name ? true : false;
  var workspace = null;
  if (this.sourceBlock_) {
    workspace = this.sourceBlock_.workspace;
  }
  if (workspace) {
    var variableTypes = this.getVariableTypes_();
    var variableModelList = [];
    // Get a copy of the list, so that adding rename and new variable options
    // doesn't modify the workspace's list.
    for (var i = 0; i < variableTypes.length; i++) {
      var variableType = variableTypes[i];
      var variables = workspace.getVariablesOfType(variableType);
      variableModelList = variableModelList.concat(variables);
    }
    for (var i = 0; i < variableModelList.length; i++){
      if (createSelectedVariable &&
          goog.string.caseInsensitiveEquals(variableModelList[i].name, name)) {
        createSelectedVariable = false;
        break;
      }
    }
  }
  var isBroadcastType = this.variableType == Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE;
  // Ensure that the currently selected variable is an option.
  if (createSelectedVariable && workspace) {
    var newVar = null;
    if (isBroadcastType && workspace.isFlyout) {
      newVar = workspace.targetWorkspace.createVariable(name, Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE);
    } else {
      newVar = workspace.createVariable(name);
    }
    variableModelList.push(newVar);
  }
  variableModelList.sort(Blockly.VariableModel.compareByName);
  var options = [];
  for (var i = 0; i < variableModelList.length; i++) {
    // Set the uuid as the internal representation of the variable.
    options[i] = [variableModelList[i].name, variableModelList[i].getId()];
  }
  if (isBroadcastType) {
    options.push([Blockly.Msg.NEW_BROADCAST_MESSAGE, Blockly.NEW_BROADCAST_MESSAGE_ID]);
  } else {
    options.push([Blockly.Msg.RENAME_VARIABLE, Blockly.RENAME_VARIABLE_ID]);
    if (Blockly.Msg.DELETE_VARIABLE) {
      options.push([Blockly.Msg.DELETE_VARIABLE.replace('%1', name),
          Blockly.DELETE_VARIABLE_ID]);
    }
  }
  return options;
};

/**
 * Handle the selection of an item in the variable dropdown menu.
 * Special case the 'Rename variable...' and 'Delete variable...' options.
 * In the rename case, prompt the user for a new name.
 * @param {!goog.ui.Menu} menu The Menu component clicked.
 * @param {!goog.ui.MenuItem} menuItem The MenuItem selected within menu.
 */
Blockly.FieldVariable.prototype.onItemSelected = function(menu, menuItem) {
  var id = menuItem.getValue();
  // TODO(marisaleung): change setValue() to take in an id as the parameter.
  // Then remove itemText.
  var itemText;
  if (this.sourceBlock_ && this.sourceBlock_.workspace) {
    var workspace = this.sourceBlock_.workspace;
    var variable = workspace.getVariableById(id);
    // If the item selected is a variable, set itemText to the variable name.
    if (variable) {
      itemText = variable.name;
    }
    else if (id == Blockly.RENAME_VARIABLE_ID) {
      // Rename variable.
      var currentName = this.getText();
      variable = workspace.getVariable(currentName);
      Blockly.Variables.renameVariable(workspace, variable);
      return;
    } else if (id == Blockly.DELETE_VARIABLE_ID) {
      // Delete variable.
      workspace.deleteVariable(this.getText());
      return;
    } else if (id == Blockly.NEW_BROADCAST_MESSAGE_ID) {
      var thisField = this;
      var setName = function(newName) {
        if (newName) {
          thisField.setValue(newName);
        }
      };
      var broadcastMsgWkspc = workspace.isFlyout ? workspace.targetWorkspace : workspace;
      Blockly.Variables.createVariable(broadcastMsgWkspc, setName, Blockly.BROADCAST_MESSAGE_VARIABLE_TYPE);
      return;
    }

    // Call any validation function, and allow it to override.
    itemText = this.callValidator(itemText);
  }
  if (itemText !== null) {
    this.setValue(itemText);
  }
};
<|endoftext|>


<commit_before>/**
 * Usando como base o _Grafo e seu conteudo.
 * Faz uma procura em todas as conexoes dos nos disponiveis procurando a menor ligacao
 * @param {Grafo} _grafo
 * @param {type} _inicio
 * @param {type} _fim
 * @returns { Array | nulo }
 */
function Dijkstra(_grafo, _inicio, _fim) {

    console.log('new dijkstra', arguments);
    console.log('new dijkstra', _inicio,_fim);
    var t = new Date();

    var aberta = new Caminho();
    var fechada = new Caminho();
    var i = 0;
    var m = 0;
    var inicial = new No();

    inicial.dado = _inicio;
    inicial.conexoes = null;
    inicial.total = 0;

    aberta.add(inicial);

    var atual, conexoes, final, custoFinal, noFinal, c = new Conexoes();

    while (aberta.length()) {
        atual = aberta.menorNo();

        if (_fim === atual.dado)
            break;

        conexoes = _grafo.pegarConexoesNo(atual.dado);

//        console.log( atual );
        c = null;i = 0;
        m = conexoes.length;

        for (i; i < m; i++) {
            c = conexoes[i];

            if (c.paraNo.dado !== atual.dado)
                final = c.paraNo;
            else
                final = c.doNo;

            custoFinal = atual.total + c.custo;

//            console.log(i, final);
            if (fechada.contem(final)) {
//                console.log('tem na fechada ');
                continue;
            }
            else if (aberta.contem(final)) {
//                console.log('tem na aberta ');
                final = aberta.procurar(final);

                if (final.total <= custoFinal)
                    continue;
            }
            else {
//                if( final.dado === {x:100,y:150})
//                console.log('novo\n-', c,'\n-F',final,'\n-A',atual,'|\n');
                noFinal = new No();
                noFinal.dado = final.dado;
                noFinal.conexoes = [new Conexoes( atual, final, c.custo)];
                noFinal.total = custoFinal;

                if (aberta.contem(final) === false)
                    aberta.add(noFinal);
            }
        }
        aberta.sub(atual)
        fechada.add(atual)
//        console.log('atual',atual.dado,atual);
//        console.log('atual aberta caminho ', aberta.caminho());
//        console.log('atual fechada caminho ', fechada.caminho());
//        console.log('add', aberta.sub(atual));
//        console.log('sub', fechada.add(atual));
//        console.log('aberta caminho ', aberta.caminho());
//        console.log('fechada caminho ', fechada.caminho());
    }// fim while

    if (atual.dado !== _fim) {
        return null;
    }//fim if
    else {
        var control = 10;
        var caminho = [];
//        while ( atual !==null ) {
        while ( control-->0 ) {
            caminho.push(atual);
//            console.log( atual );
            if( atual.conexoes )
                atual = atual.conexoes[0].doNo;
            else break;
        }

        console.log('tempo:', new Date()-t);
        return caminho;
    }//fim else

}// fim dijkstra<commit_msg>adicionada as Referências<commit_after>/* Based on Artificial Intelligence for Games from Ian Millington (Author), John Funge (Author) */
/**
 * Usando como base o _Grafo e seu conteudo.
 * Faz uma procura em todas as conexoes dos nos disponiveis procurando a menor ligacao
 * @param {Grafo} _grafo
 * @param {type} _inicio
 * @param {type} _fim
 * @returns { Array | nulo }
 */
function Dijkstra(_grafo, _inicio, _fim) {

//    console.log('new dijkstra', arguments);
//    console.log('new dijkstra', _inicio,_fim);
    var t = new Date();

    var aberta = new Caminho();
    var fechada = new Caminho();
    var i = 0;
    var m = 0;
    var inicial = new No();

    inicial.dado = _inicio;
    inicial.conexoes = null;
    inicial.total = 0;

    aberta.add(inicial);

    var atual, conexoes, final, custoFinal, noFinal, c = new Conexoes();

    while (aberta.length()) {
        atual = aberta.menorNo();

        if (_fim === atual.dado)
            break;

        conexoes = _grafo.pegarConexoesNo(atual.dado);

//        console.log( atual );
        c = null;i = 0;
        m = conexoes.length;

        for (i; i < m; i++) {
            c = conexoes[i];

            if (c.paraNo.dado !== atual.dado)
                final = c.paraNo;
            else
                final = c.doNo;

            custoFinal = atual.total + c.custo;

//            console.log(i, final);
            if (fechada.contem(final)) {
//                console.log('tem na fechada ');
                continue;
            }
            else if (aberta.contem(final)) {
//                console.log('tem na aberta ');
                final = aberta.procurar(final);

                if (final.total <= custoFinal)
                    continue;
            }
            else {
//                if( final.dado === {x:100,y:150}) console.log('novo\n-', c,'\n-F',final,'\n-A',atual,'|\n');
                noFinal = new No();
                noFinal.dado = final.dado;
                noFinal.conexoes = [new Conexoes( atual, final, c.custo)];
                noFinal.total = custoFinal;

                if (aberta.contem(final) === false)
                    aberta.add(noFinal);
            }
        }
        aberta.sub(atual)
        fechada.add(atual)
//        console.log('atual',atual.dado,atual);
//        console.log('atual aberta caminho ', aberta.caminho());
//        console.log('atual fechada caminho ', fechada.caminho());
//        console.log('add', aberta.sub(atual));
//        console.log('sub', fechada.add(atual));
//        console.log('aberta caminho ', aberta.caminho());
//        console.log('fechada caminho ', fechada.caminho());
    }// fim while

    if (atual.dado !== _fim) {
        return null;
    }//fim if
    else {
        var control = 10;
        var caminho = [];
//        while ( atual !==null ) {
        while ( control-->0 ) {
            caminho.push(atual);
//            console.log( atual );
            if( atual.conexoes )
                atual = atual.conexoes[0].doNo;
            else break;
        }

        console.log('tempo:', new Date()-t);
        return caminho;
    }//fim else

}// fim dijkstra
<|endoftext|>


<commit_before>#! /usr/bin/env node
const path = require('path')

const every = require('lodash/every')
const argv = require('minimist')(process.argv.slice(2), {
  default: {
    bertfile: '.bert.js'
  }
})
const localBert = require('..')
const logger = require('../lib/logger')

const getTasksToLoad = () => argv._.length === 0 ? ['default'] : argv._

let countRunClears = 0

localBert.on('task_start', function ({task}) {
  console.log(logger.startTask(task))
})

localBert.on('task_stop', function ({task, duration}) {
  if (countRunClears === 0) {
    process.nextTick(() => {
      localBert.start('clear containers')
    })
  }

  console.log(logger.stopTask(task, duration))
})

localBert.on('task_err', function ({task, message, err}) {
  console.log(logger.errTask(task, message, err.stack))
  process.exit(1)
})

localBert.task('clear containers', async () => {
  countRunClears += 1

  if (every(getTasksToLoad().map(task => localBert.tasks[task].done), Boolean)) {
    await Promise.all(Object.keys(localBert.agents).map(agent => localBert.agents[agent].rmContainer({silent: !true})))
  }
})

global.bert = localBert
const bertfile = path.join(process.cwd(), argv.bertfile)

async function run () {
  /* Load task bert */
  require(bertfile)

  getTasksToLoad().map(e => localBert.start(e))
}

run()
.catch(err => console.error(err.stack))
<commit_msg>Update bin to bert<commit_after>#! /usr/bin/env node
const path = require('path')
const resolve = require('resolve')

const every = require('lodash/every')
const argv = require('minimist')(process.argv.slice(2), {
  default: {
    bertfile: '.bert.js'
  }
})
const logger = require('../lib/logger')

/* Load instance to bert */
const localBert = process.env.BERT_MODE_DEV
  ? require('..')
  : resolve('bert.js', { basedir: process.cwd() })

const getTasksToLoad = () => argv._.length === 0 ? ['default'] : argv._

let countRunClears = 0

localBert.on('task_start', function ({task}) {
  console.log(logger.startTask(task))
})

localBert.on('task_stop', function ({task, duration}) {
  if (countRunClears === 0) {
    process.nextTick(() => {
      localBert.start('clear containers')
    })
  }

  console.log(logger.stopTask(task, duration))
})

localBert.on('task_err', function ({task, message, err}) {
  console.log(logger.errTask(task, message, err.stack))
  process.exit(1)
})

localBert.task('clear containers', async () => {
  countRunClears += 1

  if (every(getTasksToLoad().map(task => localBert.tasks[task].done), Boolean)) {
    await Promise.all(Object.keys(localBert.agents).map(agent => localBert.agents[agent].rmContainer({silent: !true})))
  }
})

global.bert = localBert
const bertfile = path.join(process.cwd(), argv.bertfile)

async function run () {
  /* Load task bert */
  require(bertfile)

  getTasksToLoad().map(e => localBert.start(e))
}

run()
.catch(err => console.error(err.stack))
<|endoftext|>


<commit_before>/* @flow */

const autoBind = require('auto-bind')
const path = require('path')
const _ = require('lodash')

const { getInode } = require('./event')
const localChange = require('./change')
const logger = require('../logger')
const measureTime = require('../perftools')

/*::
import type { LocalEvent } from './event'
import type {
  LocalChange,
  LocalDirAddition,
  LocalDirDeletion,
  LocalDirMove,
  LocalFileAddition,
  LocalFileDeletion,
  LocalFileMove
} from './change'
*/

const log = logger({
  component: 'LocalAnalysis'
})

module.exports = function analysis (events /*: LocalEvent[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  const changes /*: LocalChange[] */ = analyseEvents(events, pendingChanges)
  sortBeforeSquash(changes)
  squashMoves(changes)
  finalSort(changes)
  return separatePendingChanges(changes, pendingChanges)
}

const panic = (context, description) => {
  log.error(_.merge({sentry: true}, context), description)
  throw new Error(description)
}

class LocalChangeMap {
  /*::
  changes: LocalChange[]
  changesByInode: Map<number, LocalChange>
  changesByPath: Map<string, LocalChange>
  */

  constructor () {
    this._clear()
    autoBind(this)
  }

  _clear () {
    this.changes = []
    this.changesByInode = new Map()
    this.changesByPath = new Map()
  }

  getChangeByInode (ino) {
    if (ino) return this.changesByInode.get(ino)
    else return null
  }

  withChangeByPath (path, callback) {
    return callback(this.changesByPath.get(path))
  }

  changeFound (c /*: LocalChange */) {
    this.changesByPath.set(c.path, c)
    if (typeof c.ino === 'number') this.changesByInode.set(c.ino, c)
    else this.changes.push(c)
  }

  flush () {
    const changes = this.changes
    for (let a of this.changesByInode.values()) changes.push(a)
    this._clear()
    return changes
  }
}

function analyseEvents (events /*: LocalEvent[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  const stopMeasure = measureTime('LocalWatcher#analyseEvents')
  // OPTIMIZE: new Array(events.length)
  const changeMap = new LocalChangeMap()
  const { changeFound } = changeMap

  if (pendingChanges.length > 0) {
    log.warn({changes: pendingChanges}, `Prepend ${pendingChanges.length} pending change(s)`)
    for (const a of pendingChanges) { changeFound(a) }
    pendingChanges.length = 0
  }

  log.trace('Analyze events...')

  for (let e/*: LocalEvent */ of events) {
    if (process.env.DEBUG) log.trace({currentEvent: e, path: e.path})
    try {
      // chokidar make mistakes
      if (e.type === 'unlinkDir' && e.old && e.old.docType === 'file') {
        log.warn({event: e, old: e.old, path: e.path}, 'chokidar miscategorized event (was file, event unlinkDir)')
        // $FlowFixMe
        e.type = 'unlink'
      }

      if (e.type === 'unlink' && e.old && e.old.docType === 'folder') {
        log.warn({event: e, old: e.old, path: e.path}, 'chokidar miscategorized event (was folder, event unlink)')
        // $FlowFixMe
        e.type = 'unlinkDir'
      }

      const result = analyseEvent(e, changeMap)
      if (result == null) continue // No change was found. Skip event.
      if (result === true) continue // A previous change was transformed. Nothing more to do.
      changeFound(result) // A new change was found
    } catch (err) {
      const sentry = err.name === 'InvalidLocalMoveEvent'
      log.error({err, path: e.path, sentry})
      throw err
    }
  }

  log.trace('Flatten changes map...')
  const changes /*: LocalChange[] */ = changeMap.flush()

  stopMeasure()
  return changes
}

function analyseEvent (e /*: LocalEvent */, changeMap /*: LocalChangeMap */) /*: ?LocalChange|true */ {
  const { getChangeByInode, withChangeByPath } = changeMap
  const sameInodeChange = getChangeByInode(getInode(e))

  switch (e.type) {
    case 'add':
      return (
        localChange.includeAddEventInFileMove(sameInodeChange, e) ||
        localChange.fileMoveFromUnlinkAdd(sameInodeChange, e) ||
        localChange.fileMoveIdenticalOffline(e) ||
        localChange.fileAddition(e)
      )
    case 'addDir':
      return (
        localChange.includeAddDirEventInDirMove(sameInodeChange, e) ||
        localChange.dirMoveFromUnlinkAdd(sameInodeChange, e) ||
        localChange.dirRenamingCaseOnlyFromAddAdd(sameInodeChange, e) ||
        localChange.dirMoveIdenticalOffline(e) ||
        localChange.dirAddition(e)
      )
    case 'change':
      return (
        localChange.includeChangeEventIntoFileMove(sameInodeChange, e) ||
        localChange.fileMoveFromFileDeletionChange(sameInodeChange, e) ||
        localChange.fileMoveIdentical(sameInodeChange, e) ||
        localChange.fileUpdate(e)
      )
    case 'unlink':
      {
        const moveChange /*: ?LocalFileMove */ = localChange.maybeMoveFile(sameInodeChange)
        /* istanbul ignore next */
        if (moveChange) {
          // TODO: Pending move
          panic({path: e.path, moveChange, event: e},
            'We should not have both move and unlink changes since ' +
            'checksumless adds and inode-less unlink events are dropped')
        }
      }
      return (
        localChange.fileMoveFromAddUnlink(sameInodeChange, e) ||
        localChange.fileDeletion(e) ||
        withChangeByPath(e.path, samePathChange => (
          localChange.convertFileMoveToDeletion(samePathChange) ||
          localChange.ignoreFileAdditionThenDeletion(samePathChange)
          // Otherwise, skip unlink event by multiple moves
        ))
      )
    case 'unlinkDir':
      {
        const moveChange /*: ?LocalDirMove */ = localChange.maybeMoveFolder(sameInodeChange)
        /* istanbul ignore next */
        if (moveChange) {
          // TODO: pending move
          panic({path: e.path, moveChange, event: e},
            'We should not have both move and unlinkDir changes since ' +
            'non-existing addDir and inode-less unlinkDir events are dropped')
        }
      }
      return (
        localChange.dirMoveFromAddUnlink(sameInodeChange, e) ||
        localChange.dirDeletion(e) ||
        withChangeByPath(e.path, samePathChange => (
          localChange.ignoreDirAdditionThenDeletion(samePathChange) ||
          localChange.convertDirMoveToDeletion(samePathChange)
        ))
      )
    default:
      throw new TypeError(`Unknown event type: ${e.type}`)
  }
}

// TODO: Rename according to the sort logic
function sortBeforeSquash (changes /*: LocalChange[] */) {
  log.trace('Sort changes before squash...')
  const stopMeasure = measureTime('LocalWatcher#sortBeforeSquash')
  changes.sort((a, b) => {
    if (a.type === 'DirMove' || a.type === 'FileMove') {
      if (b.type === 'DirMove' || b.type === 'FileMove') {
        if (a.path < b.path) return -1
        else if (a.path > b.path) return 1
        else return 0
      } else return -1
    } else if (b.type === 'DirMove' || b.type === 'FileMove') {
      return 1
    } else {
      return 0
    }
  })
  stopMeasure()
}

function squashMoves (changes /*: LocalChange[] */) {
  log.trace('Squash moves...')
  const stopMeasure = measureTime('LocalWatcher#squashMoves')

  for (let i = 0; i < changes.length; i++) {
    let a = changes[i]

    if (a.type !== 'DirMove' && a.type !== 'FileMove') break
    for (let j = i + 1; j < changes.length; j++) {
      let b = changes[j]
      if (b.type !== 'DirMove' && b.type !== 'FileMove') break

      // inline of LocalChange.isChildMove
      if (a.type === 'DirMove' &&
      b.path.indexOf(a.path + path.sep) === 0 &&
      a.old && b.old &&
      b.old.path.indexOf(a.old.path + path.sep) === 0) {
        log.debug({oldpath: b.old.path, path: b.path}, 'descendant move')
        a.wip = a.wip || b.wip
        if (b.path.substr(a.path.length) === b.old.path.substr(a.old.path.length)) {
          log.debug({oldpath: b.old.path, path: b.path}, 'ignoring explicit child move')
          changes.splice(j--, 1)
        } else {
          log.debug({oldpath: b.old.path, path: b.path}, 'move inside move')
          b.old.path = b.old.path.replace(a.old.path, a.path)
          b.needRefetch = true
        }
      }
    }
  }

  stopMeasure()
}

function separatePendingChanges (changes /*: LocalChange[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  log.trace('Reserve changes in progress for next flush...')

  for (let i = 0; i < changes.length; i++) {
    const change = changes[i]
    if (change.wip) {
      if (change.type === 'DirMove' || change.type === 'FileMove') {
        log.debug({
          change: change.type,
          oldpath: change.old.path,
          path: change.path,
          ino: change.ino
        }, 'incomplete change')
      } else {
        log.debug({change: change.type, path: change.path}, 'incomplete change')
      }
      pendingChanges.push(changes[i])
    } else {
      log.debug(`Identified ${changes.length} change(s).`)
      log.debug(`${pendingChanges.length} of them are still pending.`)
      return changes.slice(i)
    }
  }
  // All actions are WIP
  return []
}

// TODO: Rename according to the sort logic
const finalSorter = (a /*: LocalChange */, b /*: LocalChange */) => {
  if (a.wip && !b.wip) return -1
  if (b.wip && !a.wip) return 1

  // b is deleting something which is a children of what a adds
  if (!localChange.addPath(b) && localChange.childOf(localChange.addPath(a), localChange.delPath(b))) return 1
  // a is deleting something which is a children of what b adds
  if (!localChange.addPath(a) && localChange.childOf(localChange.addPath(b), localChange.delPath(a))) return -1

  // b is moving something which is a children of what a adds
  if (localChange.childOf(localChange.addPath(a), localChange.delPath(b))) return -1
  // a is deleting or moving something which is a children of what b adds
  if (localChange.childOf(localChange.addPath(b), localChange.delPath(a))) return 1

  // if one change is a child of another, it takes priority
  if (localChange.isChildAdd(a, b)) return -1
  if (localChange.isChildDelete(b, a)) return -1
  if (localChange.isChildAdd(b, a)) return 1
  if (localChange.isChildDelete(a, b)) return 1

  // a is deleted what b added
  if (localChange.delPath(a) === localChange.addPath(b)) return -1
  // b is deleting what a added
  if (localChange.delPath(b) === localChange.addPath(a)) return 1

  // both adds at same path (seen with move + add)
  if (localChange.addPath(a) && localChange.addPath(a) === localChange.addPath(b)) return -1
  // both deletes at same path (seen with delete + move)
  if (localChange.delPath(a) && (localChange.delPath(a) === localChange.delPath(b))) return 1

  // otherwise, order by add path
  if (localChange.lower(localChange.addPath(a), localChange.addPath(b))) return -1
  if (localChange.lower(localChange.addPath(b), localChange.addPath(a))) return 1

  // if there isnt 2 add paths, sort by del path
  if (localChange.lower(localChange.delPath(b), localChange.delPath(a))) return -1

  return 1
}

// TODO: Rename according to the sort logic
function finalSort (changes /*: LocalChange[] */) {
  log.trace('Final sort...')
  const stopMeasure = measureTime('LocalWatcher#finalSort')
  changes.sort(finalSorter)
  stopMeasure()
}
<commit_msg>core/local/analysis: Don't destructure LocalChangeMap methods<commit_after>/* @flow */

const autoBind = require('auto-bind')
const path = require('path')
const _ = require('lodash')

const { getInode } = require('./event')
const localChange = require('./change')
const logger = require('../logger')
const measureTime = require('../perftools')

/*::
import type { LocalEvent } from './event'
import type {
  LocalChange,
  LocalDirAddition,
  LocalDirDeletion,
  LocalDirMove,
  LocalFileAddition,
  LocalFileDeletion,
  LocalFileMove
} from './change'
*/

const log = logger({
  component: 'LocalAnalysis'
})

module.exports = function analysis (events /*: LocalEvent[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  const changes /*: LocalChange[] */ = analyseEvents(events, pendingChanges)
  sortBeforeSquash(changes)
  squashMoves(changes)
  finalSort(changes)
  return separatePendingChanges(changes, pendingChanges)
}

const panic = (context, description) => {
  log.error(_.merge({sentry: true}, context), description)
  throw new Error(description)
}

class LocalChangeMap {
  /*::
  changes: LocalChange[]
  changesByInode: Map<number, LocalChange>
  changesByPath: Map<string, LocalChange>
  */

  constructor () {
    this._clear()
    autoBind(this)
  }

  _clear () {
    this.changes = []
    this.changesByInode = new Map()
    this.changesByPath = new Map()
  }

  getChangeByInode (ino) {
    if (ino) return this.changesByInode.get(ino)
    else return null
  }

  withChangeByPath (path, callback) {
    return callback(this.changesByPath.get(path))
  }

  changeFound (c /*: LocalChange */) {
    this.changesByPath.set(c.path, c)
    if (typeof c.ino === 'number') this.changesByInode.set(c.ino, c)
    else this.changes.push(c)
  }

  flush () {
    const changes = this.changes
    for (let a of this.changesByInode.values()) changes.push(a)
    this._clear()
    return changes
  }
}

function analyseEvents (events /*: LocalEvent[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  const stopMeasure = measureTime('LocalWatcher#analyseEvents')
  // OPTIMIZE: new Array(events.length)
  const changeMap = new LocalChangeMap()

  if (pendingChanges.length > 0) {
    log.warn({changes: pendingChanges}, `Prepend ${pendingChanges.length} pending change(s)`)
    for (const a of pendingChanges) { changeMap.changeFound(a) }
    pendingChanges.length = 0
  }

  log.trace('Analyze events...')

  for (let e/*: LocalEvent */ of events) {
    if (process.env.DEBUG) log.trace({currentEvent: e, path: e.path})
    try {
      // chokidar make mistakes
      if (e.type === 'unlinkDir' && e.old && e.old.docType === 'file') {
        log.warn({event: e, old: e.old, path: e.path}, 'chokidar miscategorized event (was file, event unlinkDir)')
        // $FlowFixMe
        e.type = 'unlink'
      }

      if (e.type === 'unlink' && e.old && e.old.docType === 'folder') {
        log.warn({event: e, old: e.old, path: e.path}, 'chokidar miscategorized event (was folder, event unlink)')
        // $FlowFixMe
        e.type = 'unlinkDir'
      }

      const result = analyseEvent(e, changeMap)
      if (result == null) continue // No change was found. Skip event.
      if (result === true) continue // A previous change was transformed. Nothing more to do.
      changeMap.changeFound(result) // A new change was found
    } catch (err) {
      const sentry = err.name === 'InvalidLocalMoveEvent'
      log.error({err, path: e.path, sentry})
      throw err
    }
  }

  log.trace('Flatten changes map...')
  const changes /*: LocalChange[] */ = changeMap.flush()

  stopMeasure()
  return changes
}

function analyseEvent (e /*: LocalEvent */, changeMap /*: LocalChangeMap */) /*: ?LocalChange|true */ {
  const sameInodeChange = changeMap.getChangeByInode(getInode(e))

  switch (e.type) {
    case 'add':
      return (
        localChange.includeAddEventInFileMove(sameInodeChange, e) ||
        localChange.fileMoveFromUnlinkAdd(sameInodeChange, e) ||
        localChange.fileMoveIdenticalOffline(e) ||
        localChange.fileAddition(e)
      )
    case 'addDir':
      return (
        localChange.includeAddDirEventInDirMove(sameInodeChange, e) ||
        localChange.dirMoveFromUnlinkAdd(sameInodeChange, e) ||
        localChange.dirRenamingCaseOnlyFromAddAdd(sameInodeChange, e) ||
        localChange.dirMoveIdenticalOffline(e) ||
        localChange.dirAddition(e)
      )
    case 'change':
      return (
        localChange.includeChangeEventIntoFileMove(sameInodeChange, e) ||
        localChange.fileMoveFromFileDeletionChange(sameInodeChange, e) ||
        localChange.fileMoveIdentical(sameInodeChange, e) ||
        localChange.fileUpdate(e)
      )
    case 'unlink':
      {
        const moveChange /*: ?LocalFileMove */ = localChange.maybeMoveFile(sameInodeChange)
        /* istanbul ignore next */
        if (moveChange) {
          // TODO: Pending move
          panic({path: e.path, moveChange, event: e},
            'We should not have both move and unlink changes since ' +
            'checksumless adds and inode-less unlink events are dropped')
        }
      }
      return (
        localChange.fileMoveFromAddUnlink(sameInodeChange, e) ||
        localChange.fileDeletion(e) ||
        changeMap.withChangeByPath(e.path, samePathChange => (
          localChange.convertFileMoveToDeletion(samePathChange) ||
          localChange.ignoreFileAdditionThenDeletion(samePathChange)
          // Otherwise, skip unlink event by multiple moves
        ))
      )
    case 'unlinkDir':
      {
        const moveChange /*: ?LocalDirMove */ = localChange.maybeMoveFolder(sameInodeChange)
        /* istanbul ignore next */
        if (moveChange) {
          // TODO: pending move
          panic({path: e.path, moveChange, event: e},
            'We should not have both move and unlinkDir changes since ' +
            'non-existing addDir and inode-less unlinkDir events are dropped')
        }
      }
      return (
        localChange.dirMoveFromAddUnlink(sameInodeChange, e) ||
        localChange.dirDeletion(e) ||
        changeMap.withChangeByPath(e.path, samePathChange => (
          localChange.ignoreDirAdditionThenDeletion(samePathChange) ||
          localChange.convertDirMoveToDeletion(samePathChange)
        ))
      )
    default:
      throw new TypeError(`Unknown event type: ${e.type}`)
  }
}

// TODO: Rename according to the sort logic
function sortBeforeSquash (changes /*: LocalChange[] */) {
  log.trace('Sort changes before squash...')
  const stopMeasure = measureTime('LocalWatcher#sortBeforeSquash')
  changes.sort((a, b) => {
    if (a.type === 'DirMove' || a.type === 'FileMove') {
      if (b.type === 'DirMove' || b.type === 'FileMove') {
        if (a.path < b.path) return -1
        else if (a.path > b.path) return 1
        else return 0
      } else return -1
    } else if (b.type === 'DirMove' || b.type === 'FileMove') {
      return 1
    } else {
      return 0
    }
  })
  stopMeasure()
}

function squashMoves (changes /*: LocalChange[] */) {
  log.trace('Squash moves...')
  const stopMeasure = measureTime('LocalWatcher#squashMoves')

  for (let i = 0; i < changes.length; i++) {
    let a = changes[i]

    if (a.type !== 'DirMove' && a.type !== 'FileMove') break
    for (let j = i + 1; j < changes.length; j++) {
      let b = changes[j]
      if (b.type !== 'DirMove' && b.type !== 'FileMove') break

      // inline of LocalChange.isChildMove
      if (a.type === 'DirMove' &&
      b.path.indexOf(a.path + path.sep) === 0 &&
      a.old && b.old &&
      b.old.path.indexOf(a.old.path + path.sep) === 0) {
        log.debug({oldpath: b.old.path, path: b.path}, 'descendant move')
        a.wip = a.wip || b.wip
        if (b.path.substr(a.path.length) === b.old.path.substr(a.old.path.length)) {
          log.debug({oldpath: b.old.path, path: b.path}, 'ignoring explicit child move')
          changes.splice(j--, 1)
        } else {
          log.debug({oldpath: b.old.path, path: b.path}, 'move inside move')
          b.old.path = b.old.path.replace(a.old.path, a.path)
          b.needRefetch = true
        }
      }
    }
  }

  stopMeasure()
}

function separatePendingChanges (changes /*: LocalChange[] */, pendingChanges /*: LocalChange[] */) /*: LocalChange[] */ {
  log.trace('Reserve changes in progress for next flush...')

  for (let i = 0; i < changes.length; i++) {
    const change = changes[i]
    if (change.wip) {
      if (change.type === 'DirMove' || change.type === 'FileMove') {
        log.debug({
          change: change.type,
          oldpath: change.old.path,
          path: change.path,
          ino: change.ino
        }, 'incomplete change')
      } else {
        log.debug({change: change.type, path: change.path}, 'incomplete change')
      }
      pendingChanges.push(changes[i])
    } else {
      log.debug(`Identified ${changes.length} change(s).`)
      log.debug(`${pendingChanges.length} of them are still pending.`)
      return changes.slice(i)
    }
  }
  // All actions are WIP
  return []
}

// TODO: Rename according to the sort logic
const finalSorter = (a /*: LocalChange */, b /*: LocalChange */) => {
  if (a.wip && !b.wip) return -1
  if (b.wip && !a.wip) return 1

  // b is deleting something which is a children of what a adds
  if (!localChange.addPath(b) && localChange.childOf(localChange.addPath(a), localChange.delPath(b))) return 1
  // a is deleting something which is a children of what b adds
  if (!localChange.addPath(a) && localChange.childOf(localChange.addPath(b), localChange.delPath(a))) return -1

  // b is moving something which is a children of what a adds
  if (localChange.childOf(localChange.addPath(a), localChange.delPath(b))) return -1
  // a is deleting or moving something which is a children of what b adds
  if (localChange.childOf(localChange.addPath(b), localChange.delPath(a))) return 1

  // if one change is a child of another, it takes priority
  if (localChange.isChildAdd(a, b)) return -1
  if (localChange.isChildDelete(b, a)) return -1
  if (localChange.isChildAdd(b, a)) return 1
  if (localChange.isChildDelete(a, b)) return 1

  // a is deleted what b added
  if (localChange.delPath(a) === localChange.addPath(b)) return -1
  // b is deleting what a added
  if (localChange.delPath(b) === localChange.addPath(a)) return 1

  // both adds at same path (seen with move + add)
  if (localChange.addPath(a) && localChange.addPath(a) === localChange.addPath(b)) return -1
  // both deletes at same path (seen with delete + move)
  if (localChange.delPath(a) && (localChange.delPath(a) === localChange.delPath(b))) return 1

  // otherwise, order by add path
  if (localChange.lower(localChange.addPath(a), localChange.addPath(b))) return -1
  if (localChange.lower(localChange.addPath(b), localChange.addPath(a))) return 1

  // if there isnt 2 add paths, sort by del path
  if (localChange.lower(localChange.delPath(b), localChange.delPath(a))) return -1

  return 1
}

// TODO: Rename according to the sort logic
function finalSort (changes /*: LocalChange[] */) {
  log.trace('Final sort...')
  const stopMeasure = measureTime('LocalWatcher#finalSort')
  changes.sort(finalSorter)
  stopMeasure()
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

var dimensions = document.querySelector('#dimensions');
var video = document.querySelector('video');
var videoSelect = document.querySelector('select#videoSource');
var selectors = [videoSelect];
var stream;

var vgaButton = document.querySelector('#vga');
var qvgaButton = document.querySelector('#qvga');
var hdButton = document.querySelector('#hd');
var fullHdButton = document.querySelector('#full-hd');

var currentConstraints = vgaConstraints;

function gotDevices(deviceInfos) {
  // Handles being called several times to update labels. Preserve values.
  var values = selectors.map(function(select) {
    return select.value;
  });
  selectors.forEach(function(select) {
    while (select.firstChild) {
      select.removeChild(select.firstChild);
    }
  });
  for (var i = 0; i !== deviceInfos.length; ++i) {
    var deviceInfo = deviceInfos[i];
    var option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || 'camera ' + (videoSelect.length + 1);
      videoSelect.appendChild(option);
    }
  }
  selectors.forEach(function(select, selectorIndex) {
    if (Array.prototype.slice.call(select.childNodes).some(function(n) {
      return n.value === values[selectorIndex];
    })) {
      select.value = values[selectorIndex];
    }
  });
}
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

vgaButton.onclick = function() {
  getMedia(vgaConstraints);
};

qvgaButton.onclick = function() {
  getMedia(qvgaConstraints);
};

hdButton.onclick = function() {
  getMedia(hdConstraints);
};

fullHdButton.onclick = function() {
  getMedia(fullHdConstraints);
};

var qvgaConstraints = {
  video: {width: {exact: 320}, height: {exact: 240}}
};

var vgaConstraints = {
  video: {width: {exact: 640}, height: {exact: 480}}
};

var hdConstraints = {
  video: {width: {exact: 1280}, height: {exact: 720}}
};

var fullHdConstraints = {
  video: {width: {exact: 1920}, height: {exact: 1080}}
};

function gotStream(mediaStream) {
  window.stream = mediaStream; // stream available to console
  video.srcObject = mediaStream;
}

function displayVideoDimensions() {
  if (!video.videoWidth) {
    setTimeout(displayVideoDimensions, 500);
  }
  dimensions.innerHTML = 'Actual video dimensions: ' + video.videoWidth +
    'x' + video.videoHeight + 'px.';
}

video.onloadedmetadata = displayVideoDimensions;
videoSelect.onchange = start(currentConstraints);

function getMedia(constraints) {
  if (stream) {
    stream.getTracks().forEach(function(track) {
      track.stop();
    });
  }

  var videoSource = videoSelect.value;
  constraints.video.deviceId = videoSource ? {exact: videoSource} : undefined;

  navigator.mediaDevices.getUserMedia(constraints)
  .then(gotStream)
  .catch(function(e) {
    var message = 'getUserMedia error: ' + e.name;
    alert(message);
    console.log(message);
  });

  currentConstraints = constraints;
}

function handleError(error) {
  console.log('navigator.getUserMedia error: ', error);
}
<commit_msg>correct constraints setting<commit_after>/*
 *  Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree.
 */

'use strict';

var dimensions = document.querySelector('#dimensions');
var video = document.querySelector('video');
var videoSelect = document.querySelector('select#videoSource');
var selectors = [videoSelect];
var stream;

var vgaButton = document.querySelector('#vga');
var qvgaButton = document.querySelector('#qvga');
var hdButton = document.querySelector('#hd');
var fullHdButton = document.querySelector('#full-hd');

var currentConstraints = vgaConstraints;

function gotDevices(deviceInfos) {
  // Handles being called several times to update labels. Preserve values.
  var values = selectors.map(function(select) {
    return select.value;
  });
  selectors.forEach(function(select) {
    while (select.firstChild) {
      select.removeChild(select.firstChild);
    }
  });
  for (var i = 0; i !== deviceInfos.length; ++i) {
    var deviceInfo = deviceInfos[i];
    var option = document.createElement('option');
    option.value = deviceInfo.deviceId;
    if (deviceInfo.kind === 'videoinput') {
      option.text = deviceInfo.label || 'camera ' + (videoSelect.length + 1);
      videoSelect.appendChild(option);
    }
  }
  selectors.forEach(function(select, selectorIndex) {
    if (Array.prototype.slice.call(select.childNodes).some(function(n) {
      return n.value === values[selectorIndex];
    })) {
      select.value = values[selectorIndex];
    }
  });
}
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);

vgaButton.onclick = function() {
  getMedia(vgaConstraints);
};

qvgaButton.onclick = function() {
  getMedia(qvgaConstraints);
};

hdButton.onclick = function() {
  getMedia(hdConstraints);
};

fullHdButton.onclick = function() {
  getMedia(fullHdConstraints);
};

var qvgaConstraints = {
  video: {width: {exact: 320}, height: {exact: 240}}
};

var vgaConstraints = {
  video: {width: {exact: 640}, height: {exact: 480}}
};

var hdConstraints = {
  video: {width: {exact: 1280}, height: {exact: 720}}
};

var fullHdConstraints = {
  video: {width: {exact: 1920}, height: {exact: 1080}}
};

function gotStream(mediaStream) {
  window.stream = mediaStream; // stream available to console
  video.srcObject = mediaStream;
  // Refresh button list in case labels have become available
  return navigator.mediaDevices.enumerateDevices();
}

function displayVideoDimensions() {
  if (!video.videoWidth) {
    setTimeout(displayVideoDimensions, 500);
  }
  dimensions.innerHTML = 'Actual video dimensions: ' + video.videoWidth +
    'x' + video.videoHeight + 'px.';
}

video.onloadedmetadata = displayVideoDimensions;
videoSelect.onchange = start(currentConstraints);

function getMedia(constraints) {
  if (stream) {
    stream.getTracks().forEach(function(track) {
      track.stop();
    });
  }

  var videoSource = videoSelect.value;
  var videoConstraints = {
      video: {deviceId: videoSource ? {exact: videoSource} : undefined,
              width: constraints.video.width,
              height: constraints.video.height}
  };

  navigator.mediaDevices.getUserMedia(videoConstraints).
      then(gotStream).then(gotDevices).catch(handleError);

  currentConstraints = constraints;
}

function handleError(error) {
  console.log('navigator.getUserMedia error: ', error);
}
<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

/**
 * Bosco command line tool
 */
var program = require('commander');
var Bosco = require('../index');
var _ = require('lodash');
var pkg = require('../package.json');
var completion = require('../src/completion');
var fs = require('fs');
var path = require('path');
require('colors'); // No need to define elsewhere

// Go over every command in the global and local commands folder and add the options
program.boscoOptionsArray = function(boscoOptionsArray) {
  if (!boscoOptionsArray || !boscoOptionsArray.length) { return this; }

  var _this = this;

  _.forEach(boscoOptionsArray, function(boscoOption) {
    if (!boscoOption.option || !boscoOption.syntax || boscoOption.syntax.length < 2) {
        throw new Error('Error parsing bosco command');
    }

    _this.option(boscoOption.syntax[0], boscoOption.syntax[1], boscoOption.syntax[2]);
  });

  return _this;
};

var getOptionsForCommandsOnPath = function(folderPath) {
  if (!fs.existsSync(folderPath)) return [];

  var wrappedFiles = _(fs.readdirSync(folderPath));

  var wrappedCommandsArray = wrappedFiles.map(function(filename) {
    if (path.extname(filename) !== '.js') { return null; }
    var file = folderPath + filename;
    var commandFile = require(file);
    return commandFile.options;
  });

  return wrappedCommandsArray.flatten().compact().value();
};

var globalOptions = [
  {
    option: 'configFile',
    syntax: ['-c, --configFile [file]', 'Use specific config file']
  },
  {
    option: 'configPath',
    syntax: ['-p, --configPath [folder]', 'Use specific config path']
  },
  {
    option: 'environment',
    syntax: ['-e, --environment [environment]', 'Set environment to use', 'local']
  },
  {
    option: 'service',
    syntax: ['-s, --service', 'Run only with service in cwd (if bosco-service.json file exists in cwd)', false]
  },
  {
    option: 'build',
    syntax: ['-b, --build [build]', 'Set build identifier to use', 'default']
  },
  {
    option: 'repo',
    syntax: ['-r, --repo [pattern]', 'Use a specific repository (parsed as regexp)', '.*']
  },
  {
    option: 'noprompt',
    syntax: ['-n, --noprompt', 'Do not prompt for confirmation']
  },
  {
    option: 'force',
    syntax: ['-f, --force', 'Force over ride on publish even if no changes']
  },
  {
    option: 'completion',
    syntax: ['--completion [shell]','Generate the shell completion code']
  },
  {
    option: 'shellCommands',
    syntax: ['--shellCommands','Generate commands for shell completion mode [used internally]']
  }
];

var bosco = new Bosco();

var localCommandsOptions = getOptionsForCommandsOnPath(bosco.getLocalCommandFolder());
var commandOptions = getOptionsForCommandsOnPath(bosco.getGlobalCommandFolder());

var allBoscoCommands = _.union(globalOptions, localCommandsOptions, commandOptions);

program
  .version(pkg.version)
  .usage('[options] <command>')
  .boscoOptionsArray(allBoscoCommands)
  .parse(process.argv);

var options = {
  program: program,
  version: pkg.version,
  args: program.args
};

// Add all parsed options to the Bosco options
_.forEach(allBoscoCommands, function(boscoOption){
  options[boscoOption.option] = program[boscoOption.option];
});

if(program.completion) {
    completion.print(program.completion);
}

bosco.init(options);
<commit_msg>Commands: Make sure syntax etc errors in a command don't asplode bosco.<commit_after>#!/usr/bin/env node

'use strict';

/**
 * Bosco command line tool
 */
var program = require('commander');
var Bosco = require('../index');
var _ = require('lodash');
var pkg = require('../package.json');
var completion = require('../src/completion');
var fs = require('fs');
var path = require('path');
require('colors'); // No need to define elsewhere

var bosco = new Bosco();

// Go over every command in the global and local commands folder and add the options
program.boscoOptionsArray = function(boscoOptionsArray) {
  if (!boscoOptionsArray || !boscoOptionsArray.length) { return this; }

  var _this = this;

  _.forEach(boscoOptionsArray, function(boscoOption) {
    if (!boscoOption.option || !boscoOption.syntax || boscoOption.syntax.length < 2) {
        throw new Error('Error parsing bosco command');
    }

    _this.option(boscoOption.syntax[0], boscoOption.syntax[1], boscoOption.syntax[2]);
  });

  return _this;
};

var getOptionsForCommandsOnPath = function(folderPath) {
  if (!fs.existsSync(folderPath)) return [];

  var wrappedFiles = _(fs.readdirSync(folderPath));

  var wrappedCommandsArray = wrappedFiles.map(function(filename) {
    if (path.extname(filename) !== '.js') { return null; }
    var file = folderPath + filename;
    var commandFile;
    try {
      commandFile = require(file);
    } catch (err) {
      bosco.error('Error requiring command file: ' + file + ': ' + err);
      return [];
    }
    return commandFile.options;
  });

  return wrappedCommandsArray.flatten().compact().value();
};

var globalOptions = [
  {
    option: 'configFile',
    syntax: ['-c, --configFile [file]', 'Use specific config file']
  },
  {
    option: 'configPath',
    syntax: ['-p, --configPath [folder]', 'Use specific config path']
  },
  {
    option: 'environment',
    syntax: ['-e, --environment [environment]', 'Set environment to use', 'local']
  },
  {
    option: 'service',
    syntax: ['-s, --service', 'Run only with service in cwd (if bosco-service.json file exists in cwd)', false]
  },
  {
    option: 'build',
    syntax: ['-b, --build [build]', 'Set build identifier to use', 'default']
  },
  {
    option: 'repo',
    syntax: ['-r, --repo [pattern]', 'Use a specific repository (parsed as regexp)', '.*']
  },
  {
    option: 'noprompt',
    syntax: ['-n, --noprompt', 'Do not prompt for confirmation']
  },
  {
    option: 'force',
    syntax: ['-f, --force', 'Force over ride on publish even if no changes']
  },
  {
    option: 'completion',
    syntax: ['--completion [shell]','Generate the shell completion code']
  },
  {
    option: 'shellCommands',
    syntax: ['--shellCommands','Generate commands for shell completion mode [used internally]']
  }
];

var localCommandsOptions = getOptionsForCommandsOnPath(bosco.getLocalCommandFolder());
var commandOptions = getOptionsForCommandsOnPath(bosco.getGlobalCommandFolder());

var allBoscoCommands = _.union(globalOptions, localCommandsOptions, commandOptions);

program
  .version(pkg.version)
  .usage('[options] <command>')
  .boscoOptionsArray(allBoscoCommands)
  .parse(process.argv);

var options = {
  program: program,
  version: pkg.version,
  args: program.args
};

// Add all parsed options to the Bosco options
_.forEach(allBoscoCommands, function(boscoOption){
  options[boscoOption.option] = program[boscoOption.option];
});

if(program.completion) {
    completion.print(program.completion);
}

bosco.init(options);
<|endoftext|>


<commit_before>// COMBAT AND INTERACTIVITY APP

var users = [];
var enemies = [];
var level = 0;
var story = document.getElementById('story');
var flavor = document.getElementById('flavor');
var startButton = document.getElementById('startbutton');
var beginGame = document.getElementById('begingame');

var testText = document.getElementById('testtext');
var testText2 = document.getElementById('testtext2');

var heroHP = document.getElementById('herohp');
var enemyHP = document.getElementById('enemyhp');

var heroButtonsGame = document.getElementById('herobuttonsgame');

function Hero() {
  var userName = prompt('Tell us your name, Hero!');
  this.name = userName;
  this.swings = 0;
  this.hits = 0;
  this.misses = 0;
  this.alive = true;
  this.hitPoints = 100;
  users.push(this);
}

function Enemy(name, hitPoints) {
  this.name = name;
  this.hitPoints = hitPoints;
  this.alive = true;
  enemies.push(this);
}

function titleScreen() {
  flavor.style.visibility = 'visible';
  beginGame.style.visibility = 'hidden';
  startButton.style.visibility = 'visible';
  story.textContent = '';
}

function beginGame() {
  //maybe (innerHTML = '')
  flavor.style.visibility = 'visible';
  //========================
  beginGame.style.visibility = 'visible';
  startButton.style.visibility = 'hidden';
  story.textContent = 'REPLACE WITH ACTUAL STORY CONTENT';
}

function dispHero() {
  testText.textContent = 'This Displays the Hero';
  // display HP
  heroHP.textContent = 'HP: 100';
  // turn on buttons
  heroButtonsGame.style.visibility = 'visible';
}

function dispEnemy() {
  testText2.textContent = 'This Displays the Enemy';
  // display HP
  enemyHP.textContent = 'HP: 25';
}

function combatRound() {
  dispHero();
  dispEnemy();
}

titleScreen();

// function updateUserData(user) {
//   for (var i = 0; i < users.length; i++) {
//     if (user.name === users[i].name) {
//
//     }
//   }
// }

// var tern1 = new Enemy('Balthasar', 50);
flavor.style.visibility = 'hidden';
heroButtonsGame.style.visibility = 'hidden';
<commit_msg>adds hit/miss chance and turnSwap functions<commit_after>// COMBAT AND INTERACTIVITY APP

var users = [];
var enemies = [];
var level = 0;
var heroTurn = true;
var story = document.getElementById('story');
var flavor = document.getElementById('flavor');
var startButton = document.getElementById('startbutton');
var beginGame = document.getElementById('begingame');

var testText = document.getElementById('testtext');
var testText2 = document.getElementById('testtext2');

var heroHP = document.getElementById('herohp');
var enemyHP = document.getElementById('enemyhp');

var heroButtonsGame = document.getElementById('herobuttonsgame');

function Hero() {
  var userName = prompt('Tell us your name, Hero!');
  this.name = userName;
  this.swings = 0;
  this.hits = 0;
  this.misses = 0;
  this.alive = true;
  this.hitPoints = 100;
  users.push(this);
}

function Enemy(name, hitPoints) {
  this.name = name;
  this.hitPoints = hitPoints;
  this.alive = true;
  enemies.push(this);
}

function titleScreen() {
  flavor.style.visibility = 'visible';
  beginGame.style.visibility = 'hidden';
  startButton.style.visibility = 'visible';
  story.textContent = '';
}

function beginGame() {
  //maybe (innerHTML = '')
  flavor.style.visibility = 'visible';
  //========================
  beginGame.style.visibility = 'visible';
  startButton.style.visibility = 'hidden';
  story.textContent = 'REPLACE WITH ACTUAL STORY CONTENT';
}

function dispHero() {
  testText.textContent = 'This Displays the Hero';
  // display HP
  heroHP.textContent = 'HP: 100';
  // turn on buttons
  heroButtonsGame.style.visibility = 'visible';
}

function dispEnemy() {
  testText2.textContent = 'This Displays the Enemy';
  // display HP
  enemyHP.textContent = 'HP: 25';
}

function combatRound() {
  dispHero();
  dispEnemy();
}

function turnSwap() {
  if (heroTurn === true) {
    heroTurn = false;
  } else {
    heroTurn = true;
  }
}

function randomHit() {
  var hit = false;
  var hitChance = Math.random();
  if (hitChance >= .6) {
    hit = true;
  }
  if (hit === false) {
    miss();
  } else {
    hit();
  }
  turnSwap();
}

function hit() {
  if (heroTurn) {
    testText2.textContent = 'HIT!';
  } else {
    textText.textContent = 'HIT!';
  }
}

function miss() {
  if (heroTurn) {
    textText2.textContent = 'miss';
  } else {
    textText.textContent = 'miss';
  }
}

titleScreen();

// function updateUserData(user) {
//   for (var i = 0; i < users.length; i++) {
//     if (user.name === users[i].name) {
//
//     }
//   }
// }

// var tern1 = new Enemy('Balthasar', 50);
flavor.style.visibility = 'hidden';
heroButtonsGame.style.visibility = 'hidden';
<|endoftext|>


<commit_before>/* multi-touch tracker with pointer events support and a hacky HUD */

var canvas,
	c, // c is the canvas' context 2D
	devicePixelRatio,
	container;

var points = [];

function draw() {
	var radiusX, radiusY, rotationAngle, pressure;
	/* hack to work around lack of orientationchange/resize event */
	if(canvas.height != window.innerHeight * devicePixelRatio) {
		resetCanvas();
	} else {
		c.clearRect(0,0,canvas.width, canvas.height);
	}
	c.strokeStyle = "#eee";
	c.lineWidth = "10";

	for (var i = 0, l = points.length; i<l; i++) {
		/* if pressure property is present and not 0, set radius, otherwise default */
		if (typeof(points[i].pressure) != 'undefined' && points[i].pressure != null) {
			radius = 35 + (points[i].pressure * 25);
		} else if (typeof(points[i].force) != 'undefined' && points[i].force != null) {
			radius = 35 + (points[i].force * 25);
		} else if (typeof(points[i].webkitForce) != 'undefined' && points[i].webkitForce != null) {
			radius = 35 + (points[i].webkitForce * 25);
		} else {
			radius = 50;
		}

		pressure = points[i].pressure || points[i].force || points[i].webkitForce|| 0.1;
		rotationAngle = points[i].rotationAngle || 0;
		if ((points[i].radiusX) && (points[i].radiusY)) {
			radiusX = points[i].radiusX;
			radiusY = points[i].radiusY;
		} else if ((points[i].width) && (points[i].width != 0) && (points[i].height) && (points[i].height != 0))  {
			radiusX = points[i].width / 2;
			radiusY = points[i].height / 2;
		} else {
			radiusX = radiusY = 40;
		}
		radiusX += pressure * 35;
		radiusY += pressure * 35;

		/* draw all circles */
		c.beginPath();
		c.ellipse(points[i].clientX, points[i].clientY, radiusX, radiusY, rotationAngle * Math.PI/180, 0, Math.PI*2, true);
		c.stroke();

		// for pointer events, add extra circle to denote a primary pointer
		if(points[i].isPrimary) {
			radiusX += 15;
			radiusY += 15;
			c.beginPath();
			c.ellipse(points[i].clientX, points[i].clientY, radiusX, radiusY, rotationAngle * Math.PI/180, 0, Math.PI*2, true);
			c.stroke();
		}

		// HUD (hacky)
		var hud_props = [];
		switch(points[i].type) {
			case undefined:
				hud_props = ['touch', 'identifier: '+points[i].identifier];
				if (points[i].touchType !== undefined) {
					hud_props.push('touchType: '+points[i].touchType);
				}
				hud_props.push('clientX: '+points[i].clientX.toFixed(5)+' clientY: '+points[i].clientY.toFixed(5));
				if ((points[i].radiusX !== undefined) && (points[i].radiusY !== undefined)) {
					hud_props.push('radiusX: '+points[i].radiusX.toFixed(5)+' radiusY: '+points[i].radiusY.toFixed(5));
				}
				if (points[i].rotationAngle !== undefined ) {
					hud_props.push('rotationAngle: '+points[i].rotationAngle.toFixed(5));
				}
				if ((points[i].altitudeAngle !== undefined) && (points[i].azimuthAngle !== undefined)) {
					hud_props.push('altitudeAngle: '+points[i].altitudeAngle.toFixed(5)+ ' azimuthAngle: '+points[i].azimuthAngle.toFixed(5));
				}
				if ((points[i].force !== undefined) || (points[i].webkitForce !== undefined)) {
					hud_props.push('force: '+((points[i].force !== undefined) ? points[i].force.toFixed(5) : points[i].webkitForce.toFixed(5)));
				}
				break;
			case 'pointerover':
			case 'pointerdown':
			case 'pointermove':
			case 'pointerup':
			case 'MSPointerOver':
			case 'MSPointerDown':
			case 'MSPointerMove':
			case 'MSPointerUp':
				hud_props = ['pointer ('+points[i].pointerType+')'+((points[i].isPrimary === true) ? ' primary' : ''), 'pointerType: '+points[i].pointerType, 'isPrimary: '+points[i].isPrimary, 'pointerId: '+points[i].pointerId, 'clientX: '+points[i].clientX.toFixed(5)+' clientY: '+points[i].clientY.toFixed(5), 'button: '+points[i].button, 'buttons: '+points[i].buttons, 'width: '+points[i].width.toFixed(5), 'height: '+points[i].height.toFixed(5), 'tiltX: '+points[i].tiltX.toFixed(5)+' tiltY: '+points[i].tiltY.toFixed(5)+' twist: '+points[i].twist.toFixed(5), 'tangentialPressure: '+points[i].tangentialPressure.toFixed(5), 'pressure: '+points[i].pressure.toFixed(5)];
				break;
			case 'mousedown':
			case 'mousemove':
			case 'mouseup':
				hud_props = ['mouse','clientX: '+points[i].clientX+' clientY: '+points[i].clientY];
				if ((points[i].force !== undefined) || (points[i].webkitForce !== undefined)) {
					hud_props.push( ((points[i].force !== undefined) ? 'force: '+points[i].force.toFixed(5) : 'webkitForce: '+points[i].webkitForce.toFixed(5)) );
				}
				break;
		}
		c.font = "30px Arial";
		c.fillStyle = "#fff";
		c.fillText(hud_props[0], points[i].clientX + radiusX + 20, points[i].clientY);
		c.fillStyle = "#aaa";
		c.font = "10px Arial";
		for (var h_i = 1, h_j = hud_props.length; h_i<h_j; h_i++) {
			c.fillText(hud_props[h_i], points[i].clientX + radiusX + 20, points[i].clientY + (h_i + 1) * 12);
		}

	}

}

function positionHandler(e) {
	if ((e.type == 'mousemove') || (e.type == 'mouseout')) {
		// remove previous mouse entry from the array (assumes only a single mouse is ever present)
		for (var i = 0, l = points.length; i<l; i++) {
			if (points[i].type == 'mousemove') {
				points.splice(i,1);
			}
		}
		if (e.type == 'mousemove') {
			// add new mouse event entry
			points.push(e);
		}
	} else if ((e.type == 'touchstart')||(e.type == 'touchmove')||(e.type == 'touchend')||(e.type == 'touchcancel')) {
		// remove any points except for mouse (to allow possibility of simultaneous mouse and touch - Chromebook Pixel?)
		for (var i = 0, l = points.length; i<l; i++) {
			if (points[i].type != 'mousemove') {
				points.splice(i,1);
				i--;
				l--;
			}
		}
		// add in all entries from the array-like targetTouches
		for (var i = 0, l = e.targetTouches.length; i<l; i++) {
			points.push(e.targetTouches[i]);
		}
		// prevent mouse compat events
		e.preventDefault();
	} else {
		/* fairly ugly, unoptimised approach of manually replicating the targetTouches array */
		switch (e.type) {
			case 'pointerdown':
			case 'pointermove':
			case 'MSPointerDown':
			case 'MSPointerMove':
				for (var i = 0, found = false, l = points.length; i<l; i++) {
					if (points[i].pointerId == e.pointerId) {
						points[i] = e;
						found = true;
						break;
					}
				}
				if (!found) {
					points.push(e);
				}
				break;
			case 'pointerup':
			case 'pointerout':
			case 'pointercancel':
			case 'MSPointerUp':
			case 'MSPointerOut':
			case 'MSPointerCancel':
				for (var i = 0, l = points.length; i<l; i++) {
					if (points[i].pointerId == e.pointerId) {
						points.splice(i,1);
						break;
					}
				}
				break;
		}
	}
	window.requestAnimationFrame(draw);
}

function init() {
	canvas = document.createElement( 'canvas' );
	c = canvas.getContext( '2d' );
	container = document.createElement( 'div' );
	container.className = "container";
	resetCanvas();
	container.appendChild(canvas);
	document.body.appendChild( container );
	// use debounced function for better performance on older/underpowered devices (e.g. Nexus 10)
	var debouncedPositionHandler = debounce(positionHandler, 5, true);
	var events = [];
	/* feature detect - in this case not dangerous, as pointer is not exclusively touch */
	if ((window.PointerEvent)||(window.navigator.pointerEnabled)||(window.navigator.msPointerEnabled)) {
		events = ['pointerover', 'pointerdown', 'pointermove', 'pointerup', 'pointerout', 'pointercancel',
		          'MSPointerOver', 'MSPointerDown', 'MSPointerMove', 'MSPointerUp', 'MSPointerOut', 'MSPointerCancel'];
	} else {
		events = ['mouseover', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
		          'touchstart', 'touchmove', 'touchend', 'touchcancel'];
	}

	for (var i=0, l=events.length; i<l; i++) {
		if ((events[i] == 'mousemove')||(events[i] == 'touchmove')) {
			canvas.addEventListener(events[i],  debouncedPositionHandler, false );
		} else {
			canvas.addEventListener(events[i],  positionHandler, false );
		}
	}

	// suppress context menu
	canvas.addEventListener('contextmenu', function(e) { e.preventDefault(); }, false)

}

function resetCanvas() {
    // HiDPI canvas adapted from http://www.html5rocks.com/en/tutorials/canvas/hidpi/
	devicePixelRatio = window.devicePixelRatio || 1;
	canvas.width = window.innerWidth * devicePixelRatio;
    canvas.height = window.innerHeight * devicePixelRatio;
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
    c.scale(devicePixelRatio, devicePixelRatio);
}

window.addEventListener('load',function() {
	/* hack to prevent firing the init script before the window object's values are populated */
	setTimeout(init,100);
},false);<commit_msg>Check that newer PointerEvents properties are actually defined...<commit_after>/* multi-touch tracker with pointer events support and a hacky HUD */

var canvas,
	c, // c is the canvas' context 2D
	devicePixelRatio,
	container;

var points = [];

function draw() {
	var radiusX, radiusY, rotationAngle, pressure;
	/* hack to work around lack of orientationchange/resize event */
	if(canvas.height != window.innerHeight * devicePixelRatio) {
		resetCanvas();
	} else {
		c.clearRect(0,0,canvas.width, canvas.height);
	}
	c.strokeStyle = "#eee";
	c.lineWidth = "10";

	for (var i = 0, l = points.length; i<l; i++) {
		/* if pressure property is present and not 0, set radius, otherwise default */
		if (typeof(points[i].pressure) != 'undefined' && points[i].pressure != null) {
			radius = 35 + (points[i].pressure * 25);
		} else if (typeof(points[i].force) != 'undefined' && points[i].force != null) {
			radius = 35 + (points[i].force * 25);
		} else if (typeof(points[i].webkitForce) != 'undefined' && points[i].webkitForce != null) {
			radius = 35 + (points[i].webkitForce * 25);
		} else {
			radius = 50;
		}

		pressure = points[i].pressure || points[i].force || points[i].webkitForce|| 0.1;
		rotationAngle = points[i].rotationAngle || 0;
		if ((points[i].radiusX) && (points[i].radiusY)) {
			radiusX = points[i].radiusX;
			radiusY = points[i].radiusY;
		} else if ((points[i].width) && (points[i].width != 0) && (points[i].height) && (points[i].height != 0))  {
			radiusX = points[i].width / 2;
			radiusY = points[i].height / 2;
		} else {
			radiusX = radiusY = 40;
		}
		radiusX += pressure * 35;
		radiusY += pressure * 35;

		/* draw all circles */
		c.beginPath();
		c.ellipse(points[i].clientX, points[i].clientY, radiusX, radiusY, rotationAngle * Math.PI/180, 0, Math.PI*2, true);
		c.stroke();

		// for pointer events, add extra circle to denote a primary pointer
		if(points[i].isPrimary) {
			radiusX += 15;
			radiusY += 15;
			c.beginPath();
			c.ellipse(points[i].clientX, points[i].clientY, radiusX, radiusY, rotationAngle * Math.PI/180, 0, Math.PI*2, true);
			c.stroke();
		}

		// HUD (hacky)
		var hud_props = [];
		switch(points[i].type) {
			case undefined:
				hud_props = ['touch', 'identifier: '+points[i].identifier];
				if (points[i].touchType !== undefined) {
					hud_props.push('touchType: '+points[i].touchType);
				}
				hud_props.push('clientX: '+points[i].clientX.toFixed(5)+' clientY: '+points[i].clientY.toFixed(5));
				if ((points[i].radiusX !== undefined) && (points[i].radiusY !== undefined)) {
					hud_props.push('radiusX: '+points[i].radiusX.toFixed(5)+' radiusY: '+points[i].radiusY.toFixed(5));
				}
				if (points[i].rotationAngle !== undefined ) {
					hud_props.push('rotationAngle: '+points[i].rotationAngle.toFixed(5));
				}
				if ((points[i].altitudeAngle !== undefined) && (points[i].azimuthAngle !== undefined)) {
					hud_props.push('altitudeAngle: '+points[i].altitudeAngle.toFixed(5)+ ' azimuthAngle: '+points[i].azimuthAngle.toFixed(5));
				}
				if ((points[i].force !== undefined) || (points[i].webkitForce !== undefined)) {
					hud_props.push('force: '+((points[i].force !== undefined) ? points[i].force.toFixed(5) : points[i].webkitForce.toFixed(5)));
				}
				break;
			case 'pointerover':
			case 'pointerdown':
			case 'pointermove':
			case 'pointerup':
			case 'MSPointerOver':
			case 'MSPointerDown':
			case 'MSPointerMove':
			case 'MSPointerUp':
				hud_props = ['pointer ('+points[i].pointerType+')'+((points[i].isPrimary === true) ? ' primary' : ''), 'pointerType: '+points[i].pointerType, 'isPrimary: '+points[i].isPrimary, 'pointerId: '+points[i].pointerId, 'clientX: '+points[i].clientX.toFixed(5)+' clientY: '+points[i].clientY.toFixed(5), 'button: '+points[i].button, 'buttons: '+points[i].buttons, 'width: '+points[i].width.toFixed(5), 'height: '+points[i].height.toFixed(5), 'tiltX: '+points[i].tiltX.toFixed(5)+' tiltY: '+points[i].tiltY.toFixed(5)];
				if ((points[i].twist !== undefined)) {
					hud_props.push('twist: '+points[i].twist.toFixed(5));
				}
				if ((points[i].tangentialPressure !== undefined)) {
					hud_props.push('tangentialPressure: '+points[i].tangentialPressure.toFixed(5));
				}
				hud_props.push('pressure: '+points[i].pressure.toFixed(5));
				break;
			case 'mousedown':
			case 'mousemove':
			case 'mouseup':
				hud_props = ['mouse','clientX: '+points[i].clientX+' clientY: '+points[i].clientY];
				if ((points[i].force !== undefined) || (points[i].webkitForce !== undefined)) {
					hud_props.push( ((points[i].force !== undefined) ? 'force: '+points[i].force.toFixed(5) : 'webkitForce: '+points[i].webkitForce.toFixed(5)) );
				}
				break;
		}
		c.font = "30px Arial";
		c.fillStyle = "#fff";
		c.fillText(hud_props[0], points[i].clientX + radiusX + 20, points[i].clientY);
		c.fillStyle = "#aaa";
		c.font = "10px Arial";
		for (var h_i = 1, h_j = hud_props.length; h_i<h_j; h_i++) {
			c.fillText(hud_props[h_i], points[i].clientX + radiusX + 20, points[i].clientY + (h_i + 1) * 12);
		}

	}

}

function positionHandler(e) {
	if ((e.type == 'mousemove') || (e.type == 'mouseout')) {
		// remove previous mouse entry from the array (assumes only a single mouse is ever present)
		for (var i = 0, l = points.length; i<l; i++) {
			if (points[i].type == 'mousemove') {
				points.splice(i,1);
			}
		}
		if (e.type == 'mousemove') {
			// add new mouse event entry
			points.push(e);
		}
	} else if ((e.type == 'touchstart')||(e.type == 'touchmove')||(e.type == 'touchend')||(e.type == 'touchcancel')) {
		// remove any points except for mouse (to allow possibility of simultaneous mouse and touch - Chromebook Pixel?)
		for (var i = 0, l = points.length; i<l; i++) {
			if (points[i].type != 'mousemove') {
				points.splice(i,1);
				i--;
				l--;
			}
		}
		// add in all entries from the array-like targetTouches
		for (var i = 0, l = e.targetTouches.length; i<l; i++) {
			points.push(e.targetTouches[i]);
		}
		// prevent mouse compat events
		e.preventDefault();
	} else {
		/* fairly ugly, unoptimised approach of manually replicating the targetTouches array */
		switch (e.type) {
			case 'pointerdown':
			case 'pointermove':
			case 'MSPointerDown':
			case 'MSPointerMove':
				for (var i = 0, found = false, l = points.length; i<l; i++) {
					if (points[i].pointerId == e.pointerId) {
						points[i] = e;
						found = true;
						break;
					}
				}
				if (!found) {
					points.push(e);
				}
				break;
			case 'pointerup':
			case 'pointerout':
			case 'pointercancel':
			case 'MSPointerUp':
			case 'MSPointerOut':
			case 'MSPointerCancel':
				for (var i = 0, l = points.length; i<l; i++) {
					if (points[i].pointerId == e.pointerId) {
						points.splice(i,1);
						break;
					}
				}
				break;
		}
	}
	window.requestAnimationFrame(draw);
}

function init() {
	canvas = document.createElement( 'canvas' );
	c = canvas.getContext( '2d' );
	container = document.createElement( 'div' );
	container.className = "container";
	resetCanvas();
	container.appendChild(canvas);
	document.body.appendChild( container );
	// use debounced function for better performance on older/underpowered devices (e.g. Nexus 10)
	var debouncedPositionHandler = debounce(positionHandler, 5, true);
	var events = [];
	/* feature detect - in this case not dangerous, as pointer is not exclusively touch */
	if ((window.PointerEvent)||(window.navigator.pointerEnabled)||(window.navigator.msPointerEnabled)) {
		events = ['pointerover', 'pointerdown', 'pointermove', 'pointerup', 'pointerout', 'pointercancel',
		          'MSPointerOver', 'MSPointerDown', 'MSPointerMove', 'MSPointerUp', 'MSPointerOut', 'MSPointerCancel'];
	} else {
		events = ['mouseover', 'mousedown', 'mousemove', 'mouseup', 'mouseout',
		          'touchstart', 'touchmove', 'touchend', 'touchcancel'];
	}

	for (var i=0, l=events.length; i<l; i++) {
		if ((events[i] == 'mousemove')||(events[i] == 'touchmove')) {
			canvas.addEventListener(events[i],  debouncedPositionHandler, false );
		} else {
			canvas.addEventListener(events[i],  positionHandler, false );
		}
	}

	// suppress context menu
	canvas.addEventListener('contextmenu', function(e) { e.preventDefault(); }, false)

}

function resetCanvas() {
    // HiDPI canvas adapted from http://www.html5rocks.com/en/tutorials/canvas/hidpi/
	devicePixelRatio = window.devicePixelRatio || 1;
	canvas.width = window.innerWidth * devicePixelRatio;
    canvas.height = window.innerHeight * devicePixelRatio;
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
    c.scale(devicePixelRatio, devicePixelRatio);
}

window.addEventListener('load',function() {
	/* hack to prevent firing the init script before the window object's values are populated */
	setTimeout(init,100);
},false);<|endoftext|>


<commit_before>test
test2<commit_msg>test3<commit_after>test
test2
test3<|endoftext|>