<commit_before>import Ember from 'ember';
import defaultHammerEvents from './hammer-events';
import dasherizedToCamel from 'ember-allpurpose/string/dasherized-to-camel';
import $eventer from './eventer';
import RegistryWalker from './registry-walker';
import jQuery from 'jquery';
import mobileDetection from './utils/is-mobile';

const eventEndings = {
  pan: ['Start','Move', 'End', 'Cancel', 'Left', 'Right', 'Up', 'Down'],
  pinch: ['Start','Move', 'End', 'Cancel', 'In', 'Out'],
  press: ['Up'],
  rotate: ['Start','Move', 'End', 'Cancel'],
  swipe: ['Left', 'Right', 'Up', 'Down'],
  tap: []
};

const {
  EventDispatcher,
  merge,
  isNone,
  set: set,
  get: get
  } = Ember;

const fmt = Ember.String.fmt;

export default EventDispatcher.extend({

  /**
   Whether or not to cache handler paths on the element
   when `useCapture` is also true.
   This needs to be replaced by a feature flag.
   @private
   @type {boolean}
   */
  useFastPaths: false,
  useCapture: false,

  canDispatchToEventManager: false,

  _gestures: null,
  _initializeGestures() {
    let list = getModuleList();

    // coalesce all the events
    let events = merge({}, defaultHammerEvents);
    list.forEach((name) => {
      let recognizer = this.container.lookupFactory('ember-gesture:recognizers/' + name);
      if (recognizer && !recognizer.ignoreEvents) {
        addEvent(events, recognizer.recognizer, name);
      }
    });

    // add them to the event dispatcher
    this.set('_gestures', events);

  },

  _fastFocus() {

    let $root = jQuery(this.get('rootElement'));
    $root.on('click.ember-gestures, touchend.ember-gestures', function (e) {

      /*
       Implements fastfocus mechanisms on mobile web/Cordova
       */
      if (mobileDetection.is()) {
        var $element = jQuery(e.currentTarget);
        var $target = jQuery(e.target);

        /*
         If the click was on an input element that needs to be able to focus, recast
         the click as a "focus" event.
         This fixes tap events on mobile where keyboardShrinksView or similar is true.
         Such devices depend on the ghost click to trigger focus, but the ghost click
         will never reach the element.
         */
        var notFocusableTypes = ['submit', 'file', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];

        //fastfocus
        if ($element.is('textarea') || ($element.is('input') && notFocusableTypes.indexOf($element.attr('type')) === -1)) {
          $element.focus();

        } else if ($target.is('textarea') || ($target.is('input') && notFocusableTypes.indexOf($target.attr('type')) === -1)) {
          $target.focus();
        }
      }

    });

  },

  willDestroy() {
    this._super();
    jQuery(this.get('rootElement')).off('.ember-gestures');
  },

  setup: function (addedEvents, rootElement) {

    this._initializeGestures();
    this._fastFocus();
    let events = this.get('events');
    let _events = merge({}, events);
    let viewRegistry = this.container.lookup('-view-registry:main') || Ember.View.views;
    let event;

    // remove undesirable events from Ember's Eventing
    if (this.get('removeTracking')) {
      _events.touchstart = null;
      _events.touchmove = null;
      _events.touchcancel = null;
      _events.touchend = null;

      _events.mousedown = null;
      _events.mouseenter = null;
      _events.mousemove = null;
      _events.mouseleave=null;
      _events.mouseup = null;

      _events.dblclick = null;
    }

    // merge custom events into Ember's Eventing
    merge(_events, addedEvents || {});

    // delete unwanted events
    for (event in _events) {
      if (_events.hasOwnProperty(event)) {
        if (!_events[event]) {
          delete events[event];
        } else {
          events[event] = _events[event];
        }
      }
    }

    // merge our events into Ember's Eventing
    merge(events, this.get('_gestures'));

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (this.get('useCapture')) {
      let walker = new RegistryWalker(viewRegistry);
      rootElement = $eventer(rootElement, walker, this.get('useFastPaths'));
    }
    for (event in events) {
      if (events.hasOwnProperty(event)) {
        this.setupHandler(rootElement, event, events[event]);
      }
    }

  }

});

function addEvent(hash, gesture, name) {
  let eventName = dasherizedToCamel(name);
  let eventBase = eventName.toLowerCase();
  let endings = eventEndings[gesture];
  hash[eventBase] = eventName;
  endings.forEach((ending) => {
    let event = eventName + ending;
    hash[event.toLowerCase()] = event;
  });
}

// this function can be replaced in ember 1.13 with a private api
// and in ember 2.0 with a potentially public api matching 1.13's
// private api. This is a stop gap for pre-ember 1.13
function getModuleList() {
  /* global requirejs */
  let list = [];
  for(var moduleName in requirejs.entries) {
    if (requirejs.entries.hasOwnProperty(moduleName)) {
      let parts = moduleName.match(/ember-gestures\/recognizers\/(.*)/);
      if (parts && parts[1].indexOf('jshint') === -1) {
        list.push(parts[1]);
      }
    }
  }
  return list;

}
<commit_msg>better destructuring<commit_after>import Ember from 'ember';
import defaultHammerEvents from './hammer-events';
import dasherizedToCamel from 'ember-allpurpose/string/dasherized-to-camel';
import $eventer from './eventer';
import RegistryWalker from './registry-walker';
import jQuery from 'jquery';
import mobileDetection from './utils/is-mobile';

const eventEndings = {
  pan: ['Start','Move', 'End', 'Cancel', 'Left', 'Right', 'Up', 'Down'],
  pinch: ['Start','Move', 'End', 'Cancel', 'In', 'Out'],
  press: ['Up'],
  rotate: ['Start','Move', 'End', 'Cancel'],
  swipe: ['Left', 'Right', 'Up', 'Down'],
  tap: []
};

const {
  EventDispatcher,
  merge,
  isNone,
  set: set,
  get: get
  } = Ember;

const { fmt } = Ember.String;

export default EventDispatcher.extend({

  /**
   Whether or not to cache handler paths on the element
   when `useCapture` is also true.
   This needs to be replaced by a feature flag.
   @private
   @type {boolean}
   */
  useFastPaths: false,
  useCapture: false,

  canDispatchToEventManager: false,

  _gestures: null,
  _initializeGestures() {
    let list = getModuleList();

    // coalesce all the events
    let events = merge({}, defaultHammerEvents);
    list.forEach((name) => {
      let recognizer = this.container.lookupFactory('ember-gesture:recognizers/' + name);
      if (recognizer && !recognizer.ignoreEvents) {
        addEvent(events, recognizer.recognizer, name);
      }
    });

    // add them to the event dispatcher
    this.set('_gestures', events);

  },

  _fastFocus() {

    let $root = jQuery(this.get('rootElement'));
    $root.on('click.ember-gestures, touchend.ember-gestures', function (e) {

      /*
       Implements fastfocus mechanisms on mobile web/Cordova
       */
      if (mobileDetection.is()) {
        var $element = jQuery(e.currentTarget);
        var $target = jQuery(e.target);

        /*
         If the click was on an input element that needs to be able to focus, recast
         the click as a "focus" event.
         This fixes tap events on mobile where keyboardShrinksView or similar is true.
         Such devices depend on the ghost click to trigger focus, but the ghost click
         will never reach the element.
         */
        var notFocusableTypes = ['submit', 'file', 'button', 'hidden', 'reset', 'range', 'radio', 'image', 'checkbox'];

        //fastfocus
        if ($element.is('textarea') || ($element.is('input') && notFocusableTypes.indexOf($element.attr('type')) === -1)) {
          $element.focus();

        } else if ($target.is('textarea') || ($target.is('input') && notFocusableTypes.indexOf($target.attr('type')) === -1)) {
          $target.focus();
        }
      }

    });

  },

  willDestroy() {
    this._super();
    jQuery(this.get('rootElement')).off('.ember-gestures');
  },

  setup: function (addedEvents, rootElement) {

    this._initializeGestures();
    this._fastFocus();
    let events = this.get('events');
    let _events = merge({}, events);
    let viewRegistry = this.container.lookup('-view-registry:main') || Ember.View.views;
    let event;

    // remove undesirable events from Ember's Eventing
    if (this.get('removeTracking')) {
      _events.touchstart = null;
      _events.touchmove = null;
      _events.touchcancel = null;
      _events.touchend = null;

      _events.mousedown = null;
      _events.mouseenter = null;
      _events.mousemove = null;
      _events.mouseleave=null;
      _events.mouseup = null;

      _events.dblclick = null;
    }

    // merge custom events into Ember's Eventing
    merge(_events, addedEvents || {});

    // delete unwanted events
    for (event in _events) {
      if (_events.hasOwnProperty(event)) {
        if (!_events[event]) {
          delete events[event];
        } else {
          events[event] = _events[event];
        }
      }
    }

    // merge our events into Ember's Eventing
    merge(events, this.get('_gestures'));

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(fmt('You cannot use the same root element (%@) multiple times in an Ember.Application', [rootElement.selector || rootElement[0].tagName]), !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (this.get('useCapture')) {
      let walker = new RegistryWalker(viewRegistry);
      rootElement = $eventer(rootElement, walker, this.get('useFastPaths'));
    }
    for (event in events) {
      if (events.hasOwnProperty(event)) {
        this.setupHandler(rootElement, event, events[event]);
      }
    }

  }

});

function addEvent(hash, gesture, name) {
  let eventName = dasherizedToCamel(name);
  let eventBase = eventName.toLowerCase();
  let endings = eventEndings[gesture];
  hash[eventBase] = eventName;
  endings.forEach((ending) => {
    let event = eventName + ending;
    hash[event.toLowerCase()] = event;
  });
}

// this function can be replaced in ember 1.13 with a private api
// and in ember 2.0 with a potentially public api matching 1.13's
// private api. This is a stop gap for pre-ember 1.13
function getModuleList() {
  /* global requirejs */
  let list = [];
  for(var moduleName in requirejs.entries) {
    if (requirejs.entries.hasOwnProperty(moduleName)) {
      let parts = moduleName.match(/ember-gestures\/recognizers\/(.*)/);
      if (parts && parts[1].indexOf('jshint') === -1) {
        list.push(parts[1]);
      }
    }
  }
  return list;

}
<|endoftext|>


<commit_before>ai = {
  boardCopy: {},
  INFINITY: 1000000000000,
  nodeCount: 0,
  limit: this.INFINITY,

  updateAIBoard : function(b) {
    var sam = new Array(b.getBoard().length);
    var ba = b.getBoard();
    for ( var i = 0; i < sam.length; i++ )
      sam[i] = ba[i].slice();

    this.boardCopy = new Board(b.getDimension(),
      b.getMoveStack().slice(),
      sam,
      b.getCurrentPlayer().toString() === "Player 1" ? 0 : 1);

    ai.nodeCount = 0;
  },

  getMove : function(b, heuristicChoice, limit) {
    this.limit = undefined;
    this.limit = limit;
    //console.log("Limiting Search By : " + this.limit);
    this.updateAIBoard(b);
    var heuristic = heuristicChoice === 1 ?
      this.maxScoreHeuristic :
      this.coinParityHeuristic;
    return {move: this.minmax(heuristic), nodes: ai.nodeCount};
  },

  maxScoreHeuristic : function(min, max) {
    return max.score;
  },

  coinParityHeuristic : function(min, max) {
    var game = ai.boardCopy;
    var board = game.getBoard();

    var maxCoin = 0,
        minCoin = 0;

    for ( var row = 0; row < game.getDimension(); row++ )
    {
      for ( var col = 0; col < game.getDimension(); col++ )
      {
        if ( board[row][col].toString() !== game.NONE.toString() )
        {
          board[row][col].toString() === max.toString() ?
            ++maxCoin :
            ++minCoin
        }
      }
    }

    return 100 * ( maxCoin - minCoin ) / (maxCoin + minCoin );
  },

  maximize : function(game, move, alpha, beta, heuristic) {
    game.play(move, game.getMoveStack(), game.getBoard());

    if (game.isGameOver(game.getBoard(), false))
    {
      var player = game.getCurrentPlayer();
      return heuristic(player.other, player);
    }

    this.getMoves(game,
      game.getCurrentPlayer()).forEach( function(move, index, moves) {
        if( ai.nodeCount < ai.limit )
        {
          ai.nodeCount++;
          alpha = Math.max(alpha, ai.minimize(game,
            move,
            alpha,
            beta,
            heuristic));
          if ( alpha >= beta ) return alpha;
        }
    });

    return alpha;
  },

  minimize : function(game, move, alpha, beta, heuristic) {
    game.play(move, game.getMoveStack(), game.getBoard());

    if (game.isGameOver(game.getBoard(), false))
    {
      var player = game.getCurrentPlayer();
      return heuristic(player.other, player);
    }

    this.getMoves(game,
      game.getCurrentPlayer()).forEach( function(move, index, moves) {
        if( ai.nodeCount < ai.limit )
        {
          ai.nodeCount++;
          beta = Math.min(beta, ai.maximize(game,
            move,
            alpha,
            beta,
            heuristic));
          if ( beta <= alpha ) return beta;
        }
    });

    return beta;
  },

  minmax : function(heuristic) {
    var max = this.boardCopy.getCurrentPlayer();

    if (this.limit === undefined)
      this.limit = this.INFINITY;

    if (this.limit < 1)
      this.limit = 1;

    alpha = -this.INFINITY;
    beta = this.INFINITY;

    var best = null;
    var value = -this.INFINITY;

    this.getMoves(this.boardCopy, max).forEach( function(move, index, moves) {
      if ( ai.nodeCount < ai.limit )
      {
        var tmpValue = ai.minimize(ai.boardCopy, move, alpha, beta, heuristic);
        if (tmpValue > value)
        {
          best = new Move(ai.boardCopy.getCurrentPlayer(),
            move,
            ai.boardCopy.getFlipGenerator(),
            ai.boardCopy.getBoard());
          value = tmpValue;
        }
      }
      else
        return best.getNewDisk();;
    });

    return best.getNewDisk();
  },

  getMoves : function (game, player) {
    var moves = [];

    for (var row = 0; row < game.getDimension(); row ++) {
      for (var col = 0; col < game.getDimension(); col ++) {
        var newDisk = new Coordinate(row, col);
        if (game.verifyMove(newDisk, player, game.getBoard())) {
          moves.push(newDisk);
        }
      }
    }

    return moves;
  }
}
<commit_msg>Fix bug for search limit == NaN<commit_after>ai = {
  boardCopy: {},
  INFINITY: 1000000000000,
  nodeCount: 0,
  limit: this.INFINITY,

  updateAIBoard : function(b) {
    var sam = new Array(b.getBoard().length);
    var ba = b.getBoard();
    for ( var i = 0; i < sam.length; i++ )
      sam[i] = ba[i].slice();

    this.boardCopy = new Board(b.getDimension(),
      b.getMoveStack().slice(),
      sam,
      b.getCurrentPlayer().toString() === "Player 1" ? 0 : 1);

    ai.nodeCount = 0;
  },

  getMove : function(b, heuristicChoice, limit) {
    this.limit = undefined;
    this.limit = limit;
    //console.log("Limiting Search By : " + this.limit);
    this.updateAIBoard(b);
    var heuristic = heuristicChoice === 1 ?
      this.maxScoreHeuristic :
      this.coinParityHeuristic;
    return {move: this.minmax(heuristic), nodes: ai.nodeCount};
  },

  maxScoreHeuristic : function(min, max) {
    return max.score;
  },

  coinParityHeuristic : function(min, max) {
    var game = ai.boardCopy;
    var board = game.getBoard();

    var maxCoin = 0,
        minCoin = 0;

    for ( var row = 0; row < game.getDimension(); row++ )
    {
      for ( var col = 0; col < game.getDimension(); col++ )
      {
        if ( board[row][col].toString() !== game.NONE.toString() )
        {
          board[row][col].toString() === max.toString() ?
            ++maxCoin :
            ++minCoin
        }
      }
    }

    return 100 * ( maxCoin - minCoin ) / (maxCoin + minCoin );
  },

  maximize : function(game, move, alpha, beta, heuristic) {
    game.play(move, game.getMoveStack(), game.getBoard());

    if (game.isGameOver(game.getBoard(), false))
    {
      var player = game.getCurrentPlayer();
      return heuristic(player.other, player);
    }

    this.getMoves(game,
      game.getCurrentPlayer()).forEach( function(move, index, moves) {
        if( ai.nodeCount < ai.limit )
        {
          ai.nodeCount++;
          alpha = Math.max(alpha, ai.minimize(game,
            move,
            alpha,
            beta,
            heuristic));
          if ( alpha >= beta ) return alpha;
        }
    });

    return alpha;
  },

  minimize : function(game, move, alpha, beta, heuristic) {
    game.play(move, game.getMoveStack(), game.getBoard());

    if (game.isGameOver(game.getBoard(), false))
    {
      var player = game.getCurrentPlayer();
      return heuristic(player.other, player);
    }

    this.getMoves(game,
      game.getCurrentPlayer()).forEach( function(move, index, moves) {
        if( ai.nodeCount < ai.limit )
        {
          ai.nodeCount++;
          beta = Math.min(beta, ai.maximize(game,
            move,
            alpha,
            beta,
            heuristic));
          if ( beta <= alpha ) return beta;
        }
    });

    return beta;
  },

  minmax : function(heuristic) {
    var max = this.boardCopy.getCurrentPlayer();

    if (this.limit === undefined || isNaN(this.limit))
      this.limit = this.INFINITY;

    if (this.limit < 1)
      this.limit = 1;

    alpha = -this.INFINITY;
    beta = this.INFINITY;

    var best = null;
    var value = -this.INFINITY;

    this.getMoves(this.boardCopy, max).forEach( function(move, index, moves) {
      if ( ai.nodeCount < ai.limit )
      {
        var tmpValue = ai.minimize(ai.boardCopy, move, alpha, beta, heuristic);
        if (tmpValue > value)
        {
          best = new Move(ai.boardCopy.getCurrentPlayer(),
            move,
            ai.boardCopy.getFlipGenerator(),
            ai.boardCopy.getBoard());
          value = tmpValue;
        }
      }
      else
        return best.getNewDisk();;
    });

    return best.getNewDisk();
  },

  getMoves : function (game, player) {
    var moves = [];

    for (var row = 0; row < game.getDimension(); row ++) {
      for (var col = 0; col < game.getDimension(); col ++) {
        var newDisk = new Coordinate(row, col);
        if (game.verifyMove(newDisk, player, game.getBoard())) {
          moves.push(newDisk);
        }
      }
    }

    return moves;
  }
}
<|endoftext|>


<commit_before>/**********************************************************************
 Freeciv - Copyright (C) 2009 - Andreas Røsdal   andrearo@pvv.ntnu.no
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

var map = {};
var tiles = {};

var DIR8_NORTHWEST = 0;
var DIR8_NORTH = 1;
var DIR8_NORTHEAST = 2;
var DIR8_WEST = 3;
var DIR8_EAST = 4;
var DIR8_SOUTHWEST = 5;
var DIR8_SOUTH = 6;
var DIR8_SOUTHEAST = 7;
var DIR8_LAST = 8;
var DIR8_COUNT = DIR8_LAST;

var TF_WRAPX = 1;
var TF_WRAPY = 2;
var TF_ISO = 4;
var TF_HEX = 8;

var T_NONE = 0; /* A special flag meaning no terrain type. */
var T_UNKNOWN = 0; /* An unknown terrain. */

/* The first terrain value. */
var T_FIRST = 0;

/* used to compute neighboring tiles.
 *
 * using
 *   x1 = x + DIR_DX[dir];
 *   y1 = y + DIR_DY[dir];
 * will give you the tile as shown below.
 *   -------
 *   |0|1|2|
 *   |-+-+-|
 *   |3| |4|
 *   |-+-+-|
 *   |5|6|7|
 *   -------
 * Note that you must normalize x1 and y1 yourself.
 */
var DIR_DX = [ -1, 0, 1, -1, 1, -1, 0, 1 ];
var DIR_DY = [ -1, -1, -1, 0, 0, 1, 1, 1 ];

/****************************************************************************
  ...
****************************************************************************/
function topo_has_flag(flag)
{
  return ((map['topology_id'] & (flag)) != 0);
}

/**************************************************************************
  Allocate space for map, and initialise the tiles.
  Uses current map.xsize and map.ysize.
**************************************************************************/
function map_allocate()
{
  /*freelog(LOG_DEBUG, "map_allocate (was %p) (%d,%d)",
	  (void *)map.tiles, map.xsize, map.ysize);*/

  /*assert(map.tiles == NULL);*/
  tiles = {};

  /* Note this use of whole_map_iterate may be a bit sketchy, since the
   * tile values (ptile->index, etc.) haven't been set yet.  It might be
   * better to do a manual loop here. */
  for (var x = 0; x < map['xsize']; x++) {
    for (var y = 0; y < map['ysize']; y++) {
      tile = {};
      tile['index'] = x + y * map['xsize'];
      tile['x'] = x;
      tile['y'] = y;
      //tile['nat_x'] = tile['index'] % map['xsize'];
      //tile['nat_y'] = Math.floor(tile['index'] / map['xsize']);
      tile = tile_init(tile);

      tiles[tile['index']] = tile;
    }
  }

  /* TODO: generate_city_map_indices(); */
  /* TODO: generate_map_indices(); */

  map['startpos_table'] = {};

  init_overview();
}

/****************************************************************************
  ...
****************************************************************************/
function tile_init(tile)
{
  tile['known'] = null;  /* tile_known in C side */
  tile['seen'] = {};     /* tile_seen in C side */
  tile['specials'] = [];
  tile['resource'] = null;
  tile['terrain'] = T_UNKNOWN;
  tile['units'] = [];
  tile['owner'] = null;
  tile['claimer'] = null;
  tile['worked'] = null;
  tile['spec_sprite'] = null;
  tile['goto_dir'] = null;
  return tile;
}

/****************************************************************************
  ...
****************************************************************************/
function map_init_topology(set_sizes)
{
  var dir;

  if (!set_sizes && is_server()) {
    /* skip this, since webclient is a client. */
  }

  /* sanity check for iso topologies*/
  /*assert(!MAP_IS_ISOMETRIC || (map.ysize % 2) == 0);*/

  /* The size and ratio must satisfy the minimum and maximum *linear*
   * restrictions on width */
  /*assert(MAP_WIDTH >= MAP_MIN_LINEAR_SIZE);
  assert(MAP_HEIGHT >= MAP_MIN_LINEAR_SIZE);
  assert(MAP_WIDTH <= MAP_MAX_LINEAR_SIZE);
  assert(MAP_HEIGHT <= MAP_MAX_LINEAR_SIZE);*/

  map.valid_dirs = {};
  map.cardinal_dirs = {};

  map.num_valid_dirs = 0;
  map.num_cardinal_dirs = 0;
  for (var dir = 0; dir < 8; dir++) {
    if (is_valid_dir(dir)) {
      map.valid_dirs[map.num_valid_dirs] = dir;
      map.num_valid_dirs++;
    }
    if (is_cardinal_dir(dir)) {
      map.cardinal_dirs[map.num_cardinal_dirs] = dir;
      map.num_cardinal_dirs++;
    }
  }
  /*assert(map.num_valid_dirs > 0 && map.num_valid_dirs <= 8);
  assert(map.num_cardinal_dirs > 0
	 && map.num_cardinal_dirs <= map.num_valid_dirs);*/

}

/****************************************************************************
  ...
****************************************************************************/
function is_valid_dir(dir)
{
  switch (dir) {
  case DIR8_SOUTHEAST:
  case DIR8_NORTHWEST:
    /* These directions are invalid in hex topologies. */
    return !(topo_has_flag(TF_HEX) && !topo_has_flag(TF_ISO));
  case DIR8_NORTHEAST:
  case DIR8_SOUTHWEST:
    /* These directions are invalid in iso-hex topologies. */
    return !(topo_has_flag(TF_HEX) && topo_has_flag(TF_ISO));
  case DIR8_NORTH:
  case DIR8_EAST:
  case DIR8_SOUTH:
  case DIR8_WEST:
    return true;
  default:
    return false;
  }
}

/****************************************************************************
  ...
****************************************************************************/
function is_cardinal_dir(dir)
{
  switch (dir) {
  case DIR8_NORTH:
  case DIR8_SOUTH:
  case DIR8_EAST:
  case DIR8_WEST:
    return true;
  case DIR8_SOUTHEAST:
  case DIR8_NORTHWEST:
    /* These directions are cardinal in iso-hex topologies. */
    return topo_has_flag(TF_HEX) && topo_has_flag(TF_ISO);
  case DIR8_NORTHEAST:
  case DIR8_SOUTHWEST:
    /* These directions are cardinal in hexagonal topologies. */
    return topo_has_flag(TF_HEX) && !topo_has_flag(TF_ISO);
  }
  return false;
}

/****************************************************************************
  Return the tile for the given cartesian (map) position.
****************************************************************************/
function map_pos_to_tile(x, y)
{
  return tiles[x + y * map['xsize']];
}

/****************************************************************************
  Return the tile for the given index.
****************************************************************************/
function index_to_tile(index)
{
  return tiles[index];
}

/****************************************************************************
  Obscure math.  See explanation in doc/HACKING.
****************************************************************************/
function NATIVE_TO_MAP_POS(nat_x, nat_y)
{
    var pmap_x = Math.floor(((nat_y) + ((nat_y) & 1)) / 2 + (nat_x));
    var pmap_y = Math.floor(nat_y - pmap_x + map['xsize']);
    return {'map_x' : pmap_x, 'map_y' : pmap_y};
}

/****************************************************************************
  ...
****************************************************************************/
function MAP_TO_NATIVE_POS(map_x, map_y)
{
   var pnat_y = Math.floor(map_x + map_y - map['xsize']);
   var pnat_x = Math.floor((2 * map_x - pnat_y - (pnat_y & 1)) / 2);
   return {'nat_y': pnat_y, 'nat_x': pnat_x};
}

/****************************************************************************
  ...
****************************************************************************/
function NATURAL_TO_MAP_POS(nat_x, nat_y)
{
   var pmap_x = Math.floor(((nat_y) + (nat_x)) / 2);
   var pmap_y = Math.floor(nat_y - pmap_x + map['xsize']);
   return {'map_x' : pmap_x, 'map_y' : pmap_y};
}

/****************************************************************************
  ...
****************************************************************************/
function MAP_TO_NATURAL_POS(map_x, map_y)
{
    var pnat_y = Math.floor((map_x) + (map_y) - map['xsize']);
    var pnat_x = Math.floor(2 * (map_x) - pnat_y);

    return {'nat_y' : pnat_y, 'nat_x' : pnat_x};
}

/****************************************************************************
  Step from the given tile in the given direction.  The new tile is returned,
  or NULL if the direction is invalid or leads off the map.
****************************************************************************/
function mapstep(ptile, dir)
{
  if (!is_valid_dir(dir)) {
    return null;
  }

  return map_pos_to_tile(DIR_DX[dir] + ptile['x'], DIR_DY[dir] + ptile['y']);
}

/**************************************************************************
Return the debugging name of the direction.
**************************************************************************/
function dir_get_name(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return "N";
  case DIR8_NORTHEAST:
    return "NE";
  case DIR8_EAST:
    return "E";
  case DIR8_SOUTHEAST:
    return "SE";
  case DIR8_SOUTH:
    return "S";
  case DIR8_SOUTHWEST:
    return "SW";
  case DIR8_WEST:
    return "W";
  case DIR8_NORTHWEST:
    return "NW";
  };

  return "[Undef]";
}

/**************************************************************************
  Returns the next direction clock-wise.
**************************************************************************/
function dir_cw(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return DIR8_NORTHEAST;
  case DIR8_NORTHEAST:
    return DIR8_EAST;
  case DIR8_EAST:
    return DIR8_SOUTHEAST;
  case DIR8_SOUTHEAST:
    return DIR8_SOUTH;
  case DIR8_SOUTH:
    return DIR8_SOUTHWEST;
  case DIR8_SOUTHWEST:
    return DIR8_WEST;
  case DIR8_WEST:
    return DIR8_NORTHWEST;
  case DIR8_NORTHWEST:
    return DIR8_NORTH;
  };

  return -1;
}

/**************************************************************************
  Returns the next direction counter-clock-wise.
**************************************************************************/
function dir_ccw(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return DIR8_NORTHWEST;
  case DIR8_NORTHEAST:
    return DIR8_NORTH;
  case DIR8_EAST:
    return DIR8_NORTHEAST;
  case DIR8_SOUTHEAST:
    return DIR8_EAST;
  case DIR8_SOUTH:
    return DIR8_SOUTHEAST;
  case DIR8_SOUTHWEST:
    return DIR8_SOUTH;
  case DIR8_WEST:
    return DIR8_SOUTHWEST;
  case DIR8_NORTHWEST:
    return DIR8_WEST;
  }
  return -1;
}

/**************************************************************************
 ...
**************************************************************************/
function clear_goto_tiles()
{
  for (var x = 0; x < map['xsize']; x++) {
    for (var y = 0; y < map['ysize']; y++) {
      tiles[x + y * map['xsize']]['goto_dir'] = null;
    }
  }
}
<commit_msg>Add temporary workaround for map wrapping bug.<commit_after>/**********************************************************************
 Freeciv - Copyright (C) 2009 - Andreas Røsdal   andrearo@pvv.ntnu.no
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2, or (at your option)
   any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
***********************************************************************/

var map = {};
var tiles = {};

var DIR8_NORTHWEST = 0;
var DIR8_NORTH = 1;
var DIR8_NORTHEAST = 2;
var DIR8_WEST = 3;
var DIR8_EAST = 4;
var DIR8_SOUTHWEST = 5;
var DIR8_SOUTH = 6;
var DIR8_SOUTHEAST = 7;
var DIR8_LAST = 8;
var DIR8_COUNT = DIR8_LAST;

var TF_WRAPX = 1;
var TF_WRAPY = 2;
var TF_ISO = 4;
var TF_HEX = 8;

var T_NONE = 0; /* A special flag meaning no terrain type. */
var T_UNKNOWN = 0; /* An unknown terrain. */

/* The first terrain value. */
var T_FIRST = 0;

/* used to compute neighboring tiles.
 *
 * using
 *   x1 = x + DIR_DX[dir];
 *   y1 = y + DIR_DY[dir];
 * will give you the tile as shown below.
 *   -------
 *   |0|1|2|
 *   |-+-+-|
 *   |3| |4|
 *   |-+-+-|
 *   |5|6|7|
 *   -------
 * Note that you must normalize x1 and y1 yourself.
 */
var DIR_DX = [ -1, 0, 1, -1, 1, -1, 0, 1 ];
var DIR_DY = [ -1, -1, -1, 0, 0, 1, 1, 1 ];

/****************************************************************************
  ...
****************************************************************************/
function topo_has_flag(flag)
{
  return ((map['topology_id'] & (flag)) != 0);
}

/**************************************************************************
  Allocate space for map, and initialise the tiles.
  Uses current map.xsize and map.ysize.
**************************************************************************/
function map_allocate()
{
  /*freelog(LOG_DEBUG, "map_allocate (was %p) (%d,%d)",
	  (void *)map.tiles, map.xsize, map.ysize);*/

  /*assert(map.tiles == NULL);*/
  tiles = {};

  /* Note this use of whole_map_iterate may be a bit sketchy, since the
   * tile values (ptile->index, etc.) haven't been set yet.  It might be
   * better to do a manual loop here. */
  for (var x = 0; x < map['xsize']; x++) {
    for (var y = 0; y < map['ysize']; y++) {
      tile = {};
      tile['index'] = x + y * map['xsize'];
      tile['x'] = x;
      tile['y'] = y;
      //tile['nat_x'] = tile['index'] % map['xsize'];
      //tile['nat_y'] = Math.floor(tile['index'] / map['xsize']);
      tile = tile_init(tile);

      tiles[tile['index']] = tile;
    }
  }

  /* TODO: generate_city_map_indices(); */
  /* TODO: generate_map_indices(); */

  map['startpos_table'] = {};

  init_overview();
}

/****************************************************************************
  ...
****************************************************************************/
function tile_init(tile)
{
  tile['known'] = null;  /* tile_known in C side */
  tile['seen'] = {};     /* tile_seen in C side */
  tile['specials'] = [];
  tile['resource'] = null;
  tile['terrain'] = T_UNKNOWN;
  tile['units'] = [];
  tile['owner'] = null;
  tile['claimer'] = null;
  tile['worked'] = null;
  tile['spec_sprite'] = null;
  tile['goto_dir'] = null;
  return tile;
}

/****************************************************************************
  ...
****************************************************************************/
function map_init_topology(set_sizes)
{
  var dir;

  if (!set_sizes && is_server()) {
    /* skip this, since webclient is a client. */
  }

  /* sanity check for iso topologies*/
  /*assert(!MAP_IS_ISOMETRIC || (map.ysize % 2) == 0);*/

  /* The size and ratio must satisfy the minimum and maximum *linear*
   * restrictions on width */
  /*assert(MAP_WIDTH >= MAP_MIN_LINEAR_SIZE);
  assert(MAP_HEIGHT >= MAP_MIN_LINEAR_SIZE);
  assert(MAP_WIDTH <= MAP_MAX_LINEAR_SIZE);
  assert(MAP_HEIGHT <= MAP_MAX_LINEAR_SIZE);*/

  map.valid_dirs = {};
  map.cardinal_dirs = {};

  map.num_valid_dirs = 0;
  map.num_cardinal_dirs = 0;
  for (var dir = 0; dir < 8; dir++) {
    if (is_valid_dir(dir)) {
      map.valid_dirs[map.num_valid_dirs] = dir;
      map.num_valid_dirs++;
    }
    if (is_cardinal_dir(dir)) {
      map.cardinal_dirs[map.num_cardinal_dirs] = dir;
      map.num_cardinal_dirs++;
    }
  }
  /*assert(map.num_valid_dirs > 0 && map.num_valid_dirs <= 8);
  assert(map.num_cardinal_dirs > 0
	 && map.num_cardinal_dirs <= map.num_valid_dirs);*/

}

/****************************************************************************
  ...
****************************************************************************/
function is_valid_dir(dir)
{
  switch (dir) {
  case DIR8_SOUTHEAST:
  case DIR8_NORTHWEST:
    /* These directions are invalid in hex topologies. */
    return !(topo_has_flag(TF_HEX) && !topo_has_flag(TF_ISO));
  case DIR8_NORTHEAST:
  case DIR8_SOUTHWEST:
    /* These directions are invalid in iso-hex topologies. */
    return !(topo_has_flag(TF_HEX) && topo_has_flag(TF_ISO));
  case DIR8_NORTH:
  case DIR8_EAST:
  case DIR8_SOUTH:
  case DIR8_WEST:
    return true;
  default:
    return false;
  }
}

/****************************************************************************
  ...
****************************************************************************/
function is_cardinal_dir(dir)
{
  switch (dir) {
  case DIR8_NORTH:
  case DIR8_SOUTH:
  case DIR8_EAST:
  case DIR8_WEST:
    return true;
  case DIR8_SOUTHEAST:
  case DIR8_NORTHWEST:
    /* These directions are cardinal in iso-hex topologies. */
    return topo_has_flag(TF_HEX) && topo_has_flag(TF_ISO);
  case DIR8_NORTHEAST:
  case DIR8_SOUTHWEST:
    /* These directions are cardinal in hexagonal topologies. */
    return topo_has_flag(TF_HEX) && !topo_has_flag(TF_ISO);
  }
  return false;
}

/****************************************************************************
  Return the tile for the given cartesian (map) position.
****************************************************************************/
function map_pos_to_tile(x, y)
{
  // FIXME: temporary workaround for map wrap bug.
  if (x >= map['xsize']) y -= 1;
  if (x < 0) y += 1;
  return tiles[x + y * map['xsize']];
}

/****************************************************************************
  Return the tile for the given index.
****************************************************************************/
function index_to_tile(index)
{
  return tiles[index];
}

/****************************************************************************
  Obscure math.  See explanation in doc/HACKING.
****************************************************************************/
function NATIVE_TO_MAP_POS(nat_x, nat_y)
{
    var pmap_x = Math.floor(((nat_y) + ((nat_y) & 1)) / 2 + (nat_x));
    var pmap_y = Math.floor(nat_y - pmap_x + map['xsize']);
    return {'map_x' : pmap_x, 'map_y' : pmap_y};
}

/****************************************************************************
  ...
****************************************************************************/
function MAP_TO_NATIVE_POS(map_x, map_y)
{
   var pnat_y = Math.floor(map_x + map_y - map['xsize']);
   var pnat_x = Math.floor((2 * map_x - pnat_y - (pnat_y & 1)) / 2);
   return {'nat_y': pnat_y, 'nat_x': pnat_x};
}

/****************************************************************************
  ...
****************************************************************************/
function NATURAL_TO_MAP_POS(nat_x, nat_y)
{
   var pmap_x = Math.floor(((nat_y) + (nat_x)) / 2);
   var pmap_y = Math.floor(nat_y - pmap_x + map['xsize']);
   return {'map_x' : pmap_x, 'map_y' : pmap_y};
}

/****************************************************************************
  ...
****************************************************************************/
function MAP_TO_NATURAL_POS(map_x, map_y)
{
    var pnat_y = Math.floor((map_x) + (map_y) - map['xsize']);
    var pnat_x = Math.floor(2 * (map_x) - pnat_y);

    return {'nat_y' : pnat_y, 'nat_x' : pnat_x};
}

/****************************************************************************
  Step from the given tile in the given direction.  The new tile is returned,
  or NULL if the direction is invalid or leads off the map.
****************************************************************************/
function mapstep(ptile, dir)
{
  if (!is_valid_dir(dir)) {
    return null;
  }

  return map_pos_to_tile(DIR_DX[dir] + ptile['x'], DIR_DY[dir] + ptile['y']);
}

/**************************************************************************
Return the debugging name of the direction.
**************************************************************************/
function dir_get_name(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return "N";
  case DIR8_NORTHEAST:
    return "NE";
  case DIR8_EAST:
    return "E";
  case DIR8_SOUTHEAST:
    return "SE";
  case DIR8_SOUTH:
    return "S";
  case DIR8_SOUTHWEST:
    return "SW";
  case DIR8_WEST:
    return "W";
  case DIR8_NORTHWEST:
    return "NW";
  };

  return "[Undef]";
}

/**************************************************************************
  Returns the next direction clock-wise.
**************************************************************************/
function dir_cw(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return DIR8_NORTHEAST;
  case DIR8_NORTHEAST:
    return DIR8_EAST;
  case DIR8_EAST:
    return DIR8_SOUTHEAST;
  case DIR8_SOUTHEAST:
    return DIR8_SOUTH;
  case DIR8_SOUTH:
    return DIR8_SOUTHWEST;
  case DIR8_SOUTHWEST:
    return DIR8_WEST;
  case DIR8_WEST:
    return DIR8_NORTHWEST;
  case DIR8_NORTHWEST:
    return DIR8_NORTH;
  };

  return -1;
}

/**************************************************************************
  Returns the next direction counter-clock-wise.
**************************************************************************/
function dir_ccw(dir)
{
  /* a switch statement is used so the ordering can be changed easily */
  switch (dir) {
  case DIR8_NORTH:
    return DIR8_NORTHWEST;
  case DIR8_NORTHEAST:
    return DIR8_NORTH;
  case DIR8_EAST:
    return DIR8_NORTHEAST;
  case DIR8_SOUTHEAST:
    return DIR8_EAST;
  case DIR8_SOUTH:
    return DIR8_SOUTHEAST;
  case DIR8_SOUTHWEST:
    return DIR8_SOUTH;
  case DIR8_WEST:
    return DIR8_SOUTHWEST;
  case DIR8_NORTHWEST:
    return DIR8_WEST;
  }
  return -1;
}

/**************************************************************************
 ...
**************************************************************************/
function clear_goto_tiles()
{
  for (var x = 0; x < map['xsize']; x++) {
    for (var y = 0; y < map['ysize']; y++) {
      tiles[x + y * map['xsize']]['goto_dir'] = null;
    }
  }
}
<|endoftext|>


<commit_before>/**
 @module ember
 @submodule ember-views
 */
import Ember from 'ember';
import jQuery from 'jquery';
import symbol from './ember-internals/symbol';

const {
  assign,
  get: get,
  set: set,
  isNone,
  run,
  Object,
  View
  } = Ember;

// PLEASE, if you are reading this code, DONT duplicate this hack :)
// This is only here so that we can test this event model prior to it landing in Ember proper.
const ActionManager = Ember.__loader.require('ember-views/system/action_manager')['default'];

/**
 `Ember.EventDispatcher` handles delegating browser events to their
 corresponding `Ember.Views.` For example, when you click on a view,
 `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
 called.

 @class EventDispatcher
 @namespace Ember
 @private
 @extends Ember.Object
 */
export default Object.extend({

  /**
   The set of events names (and associated handler function names) to be setup
   and dispatched by the `EventDispatcher`. Modifications to this list can be done
   at setup time, generally via the `Ember.Application.customEvents` hash.

   To add new events to be listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        paste: 'paste'
      }
    });
   ```

   To prevent default events from being listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        mouseenter: null,
        mouseleave: null
      }
    });
   ```
   @property events
   @type Object
   @private
   */
  events: {
    touchstart  : 'touchStart',
    touchmove   : 'touchMove',
    touchend    : 'touchEnd',
    touchcancel : 'touchCancel',
    keydown     : 'keyDown',
    keyup       : 'keyUp',
    keypress    : 'keyPress',
    mousedown   : 'mouseDown',
    mouseup     : 'mouseUp',
    contextmenu : 'contextMenu',
    click       : 'click',
    dblclick    : 'doubleClick',
    mousemove   : 'mouseMove',
    focusin     : 'focusIn',
    focusout    : 'focusOut',
    mouseenter  : 'mouseEnter',
    mouseleave  : 'mouseLeave',
    submit      : 'submit',
    input       : 'input',
    change      : 'change',
    dragstart   : 'dragStart',
    drag        : 'drag',
    dragenter   : 'dragEnter',
    dragleave   : 'dragLeave',
    dragover    : 'dragOver',
    drop        : 'drop',
    dragend     : 'dragEnd'
  },

  /**
   The root DOM element to which event listeners should be attached. Event
   listeners will be attached to the document unless this is overridden.

   Can be specified as a DOMElement or a selector string.

   The default body is a string since this may be evaluated before document.body
   exists in the DOM.

   @private
   @property rootElement
   @type DOMElement
   @default 'body'
   */
  rootElement: 'body',

  /**
   It enables events to be dispatched to the view's `eventManager.` When present,
   this object takes precedence over handling of events on the view itself.

   Note that most Ember applications do not use this feature. If your app also
   does not use it, consider setting this property to false to gain some performance
   improvement by allowing the EventDispatcher to skip the search for the
   `eventManager` on the view tree.

   ```javascript
   var EventDispatcher = Em.EventDispatcher.extend({
      events: {
          click       : 'click',
          focusin     : 'focusIn',
          focusout    : 'focusOut',
          change      : 'change'
      },
      canDispatchToEventManager: false
    });
   container.register('event_dispatcher:main', EventDispatcher);
   ```

   @property canDispatchToEventManager
   @type boolean
   @default 'true'
   @since 1.7.0
   @private
   */
  canDispatchToEventManager: true,

  /**
   Enables capturing of events immediately instead of during bubble
   @private
   */
  useCapture: true,

  /**
   Sets up event listeners for standard browser events.

   This will be called after the browser sends a `DOMContentReady` event. By
   default, it will set up all of the listeners on the document body. If you
   would like to register the listeners on a different element, set the event
   dispatcher's `root` property.

   @private
   @method setup
   @param addedEvents {Object}
   */
  setup(addedEvents, rootElement) {
    let event;
    let events = assign({}, get(this, 'events'), addedEvents);
    let viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views;
    let eventWalker;

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (get(this, 'useCapture')) {
      rootElement = rootElement.get(0);
      eventWalker = new EventWalker(viewRegistry);
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupCaptureHandler(viewRegistry, rootElement, event, events[event], eventWalker);
        }
      }
    } else {
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupBubbleHandler(viewRegistry, rootElement, event, events[event]);
        }
      }
    }
  },

  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupBubbleHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   */
  setupBubbleHandler(viewRegistry, rootElement, event, eventName) {
    var self = this;

    if (eventName === null) {
      return;
    }

    rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) {
      var view = viewRegistry[this.id];
      var result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    });

    rootElement.on(event + '.ember', '[data-ember-action]', function(evt) {
      var actionId = jQuery(evt.currentTarget).attr('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          return action.handler(evt);
        }
      }
    });
  },

  /**
   Cache for event listeners attached with `useCapture`

   @private
   */
  _handlers: [],
  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupCaptureHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   @param eventWalker an instance of a walker used to find the closest action or view element
   */
  setupCaptureHandler(viewRegistry, rootElement, event, eventName, eventWalker) {
    let self = this;

    function didFindId(evt, triggeringManager, handlers) {
      let view = viewRegistry[this.id];
      let result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      // collect handler
      if (handlers) {
        // TODO this logic needs pulled out of _dispatchEvent and _bubbleEvent
        // TODO and we should collect the actual handler, not just the element
        if (manager[eventName] && typeof manager[eventName] === 'function') {
          handlers.push(['id', this]);
        } else if (view.has(eventName)) {
          handlers.push(['id', this]);
        }
      }

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    }

    function didFindAction(evt, handlers) {
      var actionId = this.getAttribute('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          // collect handler
          // TODO this should collect the actual handler instead
          if (handlers) {
            handlers.push(['action', this]);
          }

          return action.handler(evt);
        }
      }
    }

    let filterFn = filterCaptureFunction(didFindId, didFindAction, eventWalker);
    this._handlers.push({ event: event, method: filterFn });
    rootElement.addEventListener(event, filterFn, true);
  },

  _findNearestEventManager(view, eventName) {
    var manager = null;

    while (view) {
      manager = get(view, 'eventManager');
      if (manager && manager[eventName]) { break; }

      view = get(view, 'parentView');
    }

    return manager;
  },

  _dispatchEvent(object, evt, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (typeof handler === 'function') {
      result = run(object, handler, evt, view);
      // Do not preventDefault in eventManagers.
      evt.stopPropagation();
    } else {
      result = this._bubbleEvent(view, evt, eventName);
    }

    return result;
  },

  _bubbleEvent(view, evt, eventName) {
    return view.handleEvent(eventName, evt);
  },

  destroy() {
    var rootElement = get(this, 'rootElement');
    if (get(this, 'useCapture')) {
      this._handlers.forEach(function(item) {
        rootElement.removeEventListener(item.event, item.method, true);
      });
      this._handlers = [];
      jQuery(rootElement).removeClass('ember-application');
    } else {
      jQuery(rootElement).off('.ember', '**').removeClass('ember-application');
    }
    return this._super(...arguments);
  },

  toString() {
    return '(EventDispatcher)';
  }

});

function filterCaptureFunction(eventName, idHandler, actionHandler, walker) {
  return function(e) {
    // normalize the event object
    // this also let's us set currentTarget correctly
    let event = jQuery.event.fix(e);

    let element = event.target;
    let result;
    let handlers;

    // trigger from cached handlers
    if (element._handlers && element._handlers[eventName]) {
      element._handlers[eventName].forEach((handler) => {
        event.currentTarget = handler[1];
      if (handler[0] === 'id') {
        result = idHandler.call(handler[1], event);
      } else {
        result = actionHandler.call(handler[1], event);
      }
    });
    return result;

    // collect and trigger handlers
  } else {

    element._handlers = element._handlers || {};
    handlers = element._handlers[eventName] = element._handlers[eventName] || [];

    let node;
    do {
      node = walker.closest(element);
      if (node) {
        event.currentTarget = node[1];
        if (node[0] === 'id') {
          result = idHandler.call(node[1], event, null, handlers);
        } else {
          result = actionHandler.call(node[1], event, handlers);
        }
        if (result) {
          node = node.parentNode;
        }
      }
    } while (result && node);
    return result;
  }
};
}

function EventWalker(registry) {
  this.registry = registry;
}

EventWalker.prototype.inRegistry = function EventWalker_inRegistry(id) {
  return !!this.registry[id];
};

EventWalker.prototype.closest = function EventWalker_closest(closest) {
  do {
    if (closest.id && this.inRegistry(closest.id)) {
      return ['id', closest];
    }
    if (closest.hasAttribute('data-ember-action')) {
      return ['action', closest];
    }
  } while (closest = closest.parentNode);
  return null;
};
<commit_msg>removes support for EventManager when using 'useCapture', this should be deprecated overall, and an additional notice that it doesn't work with useCapture should be added<commit_after>/**
 @module ember
 @submodule ember-views
 */
import Ember from 'ember';
import jQuery from 'jquery';
import symbol from './ember-internals/symbol';

const {
  assign,
  get: get,
  set: set,
  isNone,
  run,
  Object,
  View
  } = Ember;

// PLEASE, if you are reading this code, DONT duplicate this hack :)
// This is only here so that we can test this event model prior to it landing in Ember proper.
const ActionManager = Ember.__loader.require('ember-views/system/action_manager')['default'];

/**
 `Ember.EventDispatcher` handles delegating browser events to their
 corresponding `Ember.Views.` For example, when you click on a view,
 `Ember.EventDispatcher` ensures that that view's `mouseDown` method gets
 called.

 @class EventDispatcher
 @namespace Ember
 @private
 @extends Ember.Object
 */
export default Object.extend({

  /**
   The set of events names (and associated handler function names) to be setup
   and dispatched by the `EventDispatcher`. Modifications to this list can be done
   at setup time, generally via the `Ember.Application.customEvents` hash.

   To add new events to be listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        paste: 'paste'
      }
    });
   ```

   To prevent default events from being listened to:

   ```javascript
   var App = Ember.Application.create({
      customEvents: {
        mouseenter: null,
        mouseleave: null
      }
    });
   ```
   @property events
   @type Object
   @private
   */
  events: {
    touchstart  : 'touchStart',
    touchmove   : 'touchMove',
    touchend    : 'touchEnd',
    touchcancel : 'touchCancel',
    keydown     : 'keyDown',
    keyup       : 'keyUp',
    keypress    : 'keyPress',
    mousedown   : 'mouseDown',
    mouseup     : 'mouseUp',
    contextmenu : 'contextMenu',
    click       : 'click',
    dblclick    : 'doubleClick',
    mousemove   : 'mouseMove',
    focusin     : 'focusIn',
    focusout    : 'focusOut',
    mouseenter  : 'mouseEnter',
    mouseleave  : 'mouseLeave',
    submit      : 'submit',
    input       : 'input',
    change      : 'change',
    dragstart   : 'dragStart',
    drag        : 'drag',
    dragenter   : 'dragEnter',
    dragleave   : 'dragLeave',
    dragover    : 'dragOver',
    drop        : 'drop',
    dragend     : 'dragEnd'
  },

  /**
   The root DOM element to which event listeners should be attached. Event
   listeners will be attached to the document unless this is overridden.

   Can be specified as a DOMElement or a selector string.

   The default body is a string since this may be evaluated before document.body
   exists in the DOM.

   @private
   @property rootElement
   @type DOMElement
   @default 'body'
   */
  rootElement: 'body',

  /**
   It enables events to be dispatched to the view's `eventManager.` When present,
   this object takes precedence over handling of events on the view itself.

   Note that most Ember applications do not use this feature. If your app also
   does not use it, consider setting this property to false to gain some performance
   improvement by allowing the EventDispatcher to skip the search for the
   `eventManager` on the view tree.

   ```javascript
   var EventDispatcher = Em.EventDispatcher.extend({
      events: {
          click       : 'click',
          focusin     : 'focusIn',
          focusout    : 'focusOut',
          change      : 'change'
      },
      canDispatchToEventManager: false
    });
   container.register('event_dispatcher:main', EventDispatcher);
   ```

   @property canDispatchToEventManager
   @type boolean
   @default 'true'
   @since 1.7.0
   @private
   */
  canDispatchToEventManager: false,

  /**
   Enables capturing of events immediately instead of during bubble
   @private
   */
  useCapture: true,

  /**
   Sets up event listeners for standard browser events.

   This will be called after the browser sends a `DOMContentReady` event. By
   default, it will set up all of the listeners on the document body. If you
   would like to register the listeners on a different element, set the event
   dispatcher's `root` property.

   @private
   @method setup
   @param addedEvents {Object}
   */
  setup(addedEvents, rootElement) {
    let event;
    let events = assign({}, get(this, 'events'), addedEvents);
    let viewRegistry = this.container && this.container.lookup('-view-registry:main') || View.views;
    let eventWalker;

    if (!isNone(rootElement)) {
      set(this, 'rootElement', rootElement);
    }

    rootElement = jQuery(get(this, 'rootElement'));

    Ember.assert(`You cannot use the same root element (${rootElement.selector || rootElement[0].tagName}) multiple times in an Ember.Application`, !rootElement.is('.ember-application'));
    Ember.assert('You cannot make a new Ember.Application using a root element that is a descendent of an existing Ember.Application', !rootElement.closest('.ember-application').length);
    Ember.assert('You cannot make a new Ember.Application using a root element that is an ancestor of an existing Ember.Application', !rootElement.find('.ember-application').length);

    rootElement.addClass('ember-application');

    Ember.assert('Unable to add "ember-application" class to rootElement. Make sure you set rootElement to the body or an element in the body.', rootElement.is('.ember-application'));

    if (get(this, 'useCapture')) {
      rootElement = rootElement.get(0);
      eventWalker = new EventWalker(viewRegistry);
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupCaptureHandler(viewRegistry, rootElement, event, events[event], eventWalker);
        }
      }
    } else {
      for (event in events) {
        if (events.hasOwnProperty(event)) {
          this.setupBubbleHandler(viewRegistry, rootElement, event, events[event]);
        }
      }
    }
  },

  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupBubbleHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   */
  setupBubbleHandler(viewRegistry, rootElement, event, eventName) {
    var self = this;

    if (eventName === null) {
      return;
    }

    rootElement.on(event + '.ember', '.ember-view', function(evt, triggeringManager) {
      var view = viewRegistry[this.id];
      var result = true;

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      if (manager && manager !== triggeringManager) {
        result = self._dispatchEvent(manager, evt, eventName, view);
      } else if (view) {
        result = self._bubbleEvent(view, evt, eventName);
      }

      return result;
    });

    rootElement.on(event + '.ember', '[data-ember-action]', function(evt) {
      var actionId = jQuery(evt.currentTarget).attr('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          return action.handler(evt);
        }
      }
    });
  },

  /**
   Cache for event listeners attached with `useCapture`

   @private
   */
  _handlers: [],
  /**
   Registers an event listener on the rootElement. If the given event is
   triggered, the provided event handler will be triggered on the target view.

   If the target view does not implement the event handler, or if the handler
   returns `false`, the parent view will be called. The event will continue to
   bubble to each successive parent view until it reaches the top.

   @private
   @method setupCaptureHandler
   @param viewRegistry registry for ember views
   @param {Element} rootElement
   @param {String} event the browser-originated event to listen to
   @param {String} eventName the name of the method to call on the view
   @param eventWalker an instance of a walker used to find the closest action or view element
   */
  setupCaptureHandler(viewRegistry, rootElement, event, eventName, eventWalker) {
    let self = this;

    function didFindId(evt, handlers) {
      let view = viewRegistry[this.id];

      var manager = self.canDispatchToEventManager ? self._findNearestEventManager(view, eventName) : null;

      // collect handler
      if (handlers) {
        // TODO this logic needs pulled out of _dispatchEvent and _bubbleEvent
        // TODO and we should collect the actual handler, not just the element
        if (manager[eventName] && typeof manager[eventName] === 'function') {
          handlers.push(['id', this]);
        } else if (view.has(eventName)) {
          handlers.push(['id', this]);
        }
      }

      return view ? self._bubbleEvent(view, evt, eventName) : true;
    }

    function didFindAction(evt, handlers) {
      var actionId = this.getAttribute('data-ember-action');
      var actions   = ActionManager.registeredActions[actionId];

      // We have to check for actions here since in some cases, jQuery will trigger
      // an event on `removeChild` (i.e. focusout) after we've already torn down the
      // action handlers for the view.
      if (!actions) {
        return;
      }

      for (let index = 0, length = actions.length; index < length; index++) {
        let action = actions[index];

        if (action && action.eventName === eventName) {
          // collect handler
          // TODO this should collect the actual handler instead
          if (handlers) {
            handlers.push(['action', this]);
          }

          return action.handler(evt);
        }
      }
    }

    let filterFn = filterCaptureFunction(didFindId, didFindAction, eventWalker);
    this._handlers.push({ event: event, method: filterFn });
    rootElement.addEventListener(event, filterFn, true);
  },

  _findNearestEventManager(view, eventName) {
    var manager = null;

    while (view) {
      manager = get(view, 'eventManager');
      if (manager && manager[eventName]) { break; }

      view = get(view, 'parentView');
    }

    return manager;
  },

  _dispatchEvent(object, evt, eventName, view) {
    var result = true;

    var handler = object[eventName];
    if (typeof handler === 'function') {
      result = run(object, handler, evt, view);
      // Do not preventDefault in eventManagers.
      evt.stopPropagation();
    } else {
      result = this._bubbleEvent(view, evt, eventName);
    }

    return result;
  },

  _bubbleEvent(view, evt, eventName) {
    return view.handleEvent(eventName, evt);
  },

  destroy() {
    var rootElement = get(this, 'rootElement');
    if (get(this, 'useCapture')) {
      this._handlers.forEach(function(item) {
        rootElement.removeEventListener(item.event, item.method, true);
      });
      this._handlers = [];
      jQuery(rootElement).removeClass('ember-application');
    } else {
      jQuery(rootElement).off('.ember', '**').removeClass('ember-application');
    }
    return this._super(...arguments);
  },

  toString() {
    return '(EventDispatcher)';
  }

});

function filterCaptureFunction(eventName, idHandler, actionHandler, walker) {
  return function(e) {
    // normalize the event object
    // this also let's us set currentTarget correctly
    let event = jQuery.event.fix(e);

    let element = event.target;
    let result;
    let handlers;

    // trigger from cached handlers
    if (element._handlers && element._handlers[eventName]) {
      element._handlers[eventName].forEach((handler) => {
        event.currentTarget = handler[1];
      if (handler[0] === 'id') {
        result = idHandler.call(handler[1], event);
      } else {
        result = actionHandler.call(handler[1], event);
      }
    });
    return result;

    // collect and trigger handlers
  } else {

    element._handlers = element._handlers || {};
    handlers = element._handlers[eventName] = element._handlers[eventName] || [];

    let node;
    do {
      node = walker.closest(element);
      if (node) {
        event.currentTarget = node[1];
        if (node[0] === 'id') {
          result = idHandler.call(node[1], event, handlers);
        } else {
          result = actionHandler.call(node[1], event, handlers);
        }
        if (result) {
          node = node.parentNode;
        }
      }
    } while (result && node);
    return result;
  }
};
}

function EventWalker(registry) {
  this.registry = registry;
}

EventWalker.prototype.inRegistry = function EventWalker_inRegistry(id) {
  return !!this.registry[id];
};

EventWalker.prototype.closest = function EventWalker_closest(closest) {
  do {
    if (closest.id && this.inRegistry(closest.id)) {
      return ['id', closest];
    }
    if (closest.hasAttribute('data-ember-action')) {
      return ['action', closest];
    }
  } while (closest = closest.parentNode);
  return null;
};
<|endoftext|>


<commit_before>/*global System, beforeEach, afterEach, describe, it*/

import { expect } from "mocha-es6";
import { removeDir, createFiles } from "./helpers.js";

import { getSystem, removeSystem } from "../src/system.js";
import module from "../src/module.js";

var dir = System.decanonicalize("lively.modules/tests/"),
    testProjectDir = dir + "test-dir-imports-exports/",
    testProjectSpec = {
      "package.json": '{"name": "imports-exports-test-project", "main": "file2.js"}',
      "file1.js": "var x = 1; var y = x;",

      "file2.js": "export var x = 1;",
      "file3.js": "import { x } from './file2.js'; var y = x;",
      "file4.js": "import { x as xx } from './file2.js'; var y = xx;",

      "file5.js": "export { x } from './file2.js';",
      "file6.js": "import { x } from './file5.js'; var y = x;",

      "file7.js": "export { x as xx } from './file2.js';",
      "file8.js": "import { xx } from './file7.js'; var y = xx;",

      "file9.js": "var x = 1; export { x };",
      "file10.js": "import { x } from './file9.js'; var y = x;",

      "file11.js": "export default 23;",
      "file12.js": "import x from './file11.js'; var y = x;",

      "file13.js": "var x = 1; export default x;",
      "file14.js": "import y from './file13.js'; var z = y;",

      "file15.js": "export default async function foo() {}",
      "file16.js": "import f from './file15.js'; f();",

      "file17.js": "export function bar() {}",
      "file18.js": "import { bar } from './file17.js'; bar();",

      "file19.js": "import { x } from './file2.js'; export { x };",
      "file20.js": "import { x } from './file19.js'; var y = x;"

    };

describe("imports and exports", () => {

  var S, modules;
  beforeEach(() => {
    S = getSystem('import-export-test');
    modules = Object.keys(testProjectSpec)
                    .map(k => module(S, testProjectDir + k));
    return createFiles(testProjectDir, testProjectSpec)
  });
  afterEach(() => removeDir(testProjectDir));

  it("references within module", async () => {
    const decls = await modules[1].declarationsForRefAt(19);
    expect(decls).to.containSubset([{
      id : {start: 4, end: 5, name: "x"},
      start: 4,
      end: 9,
      module: {id: testProjectDir + "file1.js"}
    }]);
  });

  it("export named declaration", async () => {
    const decls = await modules[3].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file3.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("export named declaration as", async () => {
    const decls = await modules[4].declarationsForRefAt(47);
    expect(decls).to.containSubset([{
      start: 14,
      end: 16,
      name: "xx",
      module: {id: testProjectDir + "file4.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export named declaration", async () => {
    const decls = await modules[6].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file6.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export named declaration as", async () => {
    const decls = await modules[8].declarationsForRefAt(42);
    expect(decls).to.containSubset([{
      start: 9,
      end: 11,
      name: "xx",
      module: {id: testProjectDir + "file8.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export indirectly", async () => {
    const decls = await modules[20].declarationsForRefAt(42);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file20.js"}
    },{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file19.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("export named id", async () => {
    const decls = await modules[10].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file10.js"}
    },{
      start: 4,
      end: 9,
      id: {start: 4, end: 5, name: "x"},
      module: {id: testProjectDir + "file9.js"}
    }]);
  });

  it("export default expr", async () => {
    const decls = await modules[12].declarationsForRefAt(38);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "x",
      module: {id: testProjectDir + "file12.js"}
    },{
      start: 15,
      end: 17,
      type: "Literal",
      module: {id: testProjectDir + "file11.js"}
    }]);
  });

  it("export default id", async () => {
    const decls = await modules[14].declarationsForRefAt(38);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "y",
      module: {id: testProjectDir + "file14.js"}
    },{
      start: 4,
      end: 9,
      id: {start: 4, end: 5, name: "x"},
      module: {id: testProjectDir + "file13.js"}
    }]);
  });

  it("export default function", async () => {
    const decls = await modules[16].declarationsForRefAt(30);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "f",
      module: {id: testProjectDir + "file16.js"}
    },{
      start: 15,
      end: 38,
      type: "FunctionDeclaration",
      module: {id: testProjectDir + "file15.js"}
    }]);
  });

  it("export named function", async () => {
    const decls = await modules[18].declarationsForRefAt(36);
    expect(decls).to.containSubset([{
      start: 9,
      end: 12,
      name: "bar",
      module: {id: testProjectDir + "file18.js"}
    },{
      start: 7,
      end: 24,
      type: "FunctionDeclaration",
      module: {id: testProjectDir + "file17.js"}
    }]);
  });
});
<commit_msg>added test for loading by package name<commit_after>/*global System, beforeEach, afterEach, describe, it*/

import { expect } from "mocha-es6";
import { removeDir, createFiles } from "./helpers.js";

import { getSystem, removeSystem } from "../src/system.js";
import module from "../src/module.js";
import { registerPackage } from "../src/packages.js";

var dir = System.decanonicalize("lively.modules/tests/"),
    testProjectDir = dir + "test-dir-imports-exports/",
    testProjectSpec = {
      "package.json": '{"name": "imports-exports-test-project", "main": "file2.js"}',
      "file1.js": "var x = 1; var y = x;",

      "file2.js": "export var x = 1;",
      "file3.js": "import { x } from './file2.js'; var y = x;",
      "file4.js": "import { x as xx } from './file2.js'; var y = xx;",

      "file5.js": "export { x } from './file2.js';",
      "file6.js": "import { x } from './file5.js'; var y = x;",

      "file7.js": "export { x as xx } from './file2.js';",
      "file8.js": "import { xx } from './file7.js'; var y = xx;",

      "file9.js": "var x = 1; export { x };",
      "file10.js": "import { x } from './file9.js'; var y = x;",

      "file11.js": "export default 23;",
      "file12.js": "import x from './file11.js'; var y = x;",

      "file13.js": "var x = 1; export default x;",
      "file14.js": "import y from './file13.js'; var z = y;",

      "file15.js": "export default async function foo() {}",
      "file16.js": "import f from './file15.js'; f();",

      "file17.js": "export function bar() {}",
      "file18.js": "import { bar } from './file17.js'; bar();",

      "file19.js": "import { x } from './file2.js'; export { x };",
      "file20.js": "import { x } from './file19.js'; var y = x;",

      "file21.js": "import { x } from 'imports-exports-test-project'; var y = x;"

    };

describe("imports and exports", () => {

  var S, modules;
  beforeEach(() => {
    S = getSystem('import-export-test');
    modules = Object.keys(testProjectSpec)
                    .map(k => module(S, testProjectDir + k));
    return createFiles(testProjectDir, testProjectSpec)
  });
  afterEach(() => removeDir(testProjectDir));

  it("references within module", async () => {
    const decls = await modules[1].declarationsForRefAt(19);
    expect(decls).to.containSubset([{
      id : {start: 4, end: 5, name: "x"},
      start: 4,
      end: 9,
      module: {id: testProjectDir + "file1.js"}
    }]);
  });

  it("export named declaration", async () => {
    const decls = await modules[3].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file3.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("export named declaration as", async () => {
    const decls = await modules[4].declarationsForRefAt(47);
    expect(decls).to.containSubset([{
      start: 14,
      end: 16,
      name: "xx",
      module: {id: testProjectDir + "file4.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export named declaration", async () => {
    const decls = await modules[6].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file6.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export named declaration as", async () => {
    const decls = await modules[8].declarationsForRefAt(42);
    expect(decls).to.containSubset([{
      start: 9,
      end: 11,
      name: "xx",
      module: {id: testProjectDir + "file8.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("re-export indirectly", async () => {
    const decls = await modules[20].declarationsForRefAt(42);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file20.js"}
    },{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file19.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });

  it("export named id", async () => {
    const decls = await modules[10].declarationsForRefAt(41);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file10.js"}
    },{
      start: 4,
      end: 9,
      id: {start: 4, end: 5, name: "x"},
      module: {id: testProjectDir + "file9.js"}
    }]);
  });

  it("export default expr", async () => {
    const decls = await modules[12].declarationsForRefAt(38);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "x",
      module: {id: testProjectDir + "file12.js"}
    },{
      start: 15,
      end: 17,
      type: "Literal",
      module: {id: testProjectDir + "file11.js"}
    }]);
  });

  it("export default id", async () => {
    const decls = await modules[14].declarationsForRefAt(38);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "y",
      module: {id: testProjectDir + "file14.js"}
    },{
      start: 4,
      end: 9,
      id: {start: 4, end: 5, name: "x"},
      module: {id: testProjectDir + "file13.js"}
    }]);
  });

  it("export default function", async () => {
    const decls = await modules[16].declarationsForRefAt(30);
    expect(decls).to.containSubset([{
      start: 7,
      end: 8,
      name: "f",
      module: {id: testProjectDir + "file16.js"}
    },{
      start: 15,
      end: 38,
      type: "FunctionDeclaration",
      module: {id: testProjectDir + "file15.js"}
    }]);
  });

  it("export named function", async () => {
    const decls = await modules[18].declarationsForRefAt(36);
    expect(decls).to.containSubset([{
      start: 9,
      end: 12,
      name: "bar",
      module: {id: testProjectDir + "file18.js"}
    },{
      start: 7,
      end: 24,
      type: "FunctionDeclaration",
      module: {id: testProjectDir + "file17.js"}
    }]);
  });

  it("export named declaration from package", async () => {
    await registerPackage(S, testProjectDir);
    const decls = await modules[21].declarationsForRefAt(59);
    expect(decls).to.containSubset([{
      start: 9,
      end: 10,
      name: "x",
      module: {id: testProjectDir + "file21.js"}
    },{
      start: 11,
      end: 16,
      id: {start: 11, end: 12, name: "x"},
      module: {id: testProjectDir + "file2.js"}
    }]);
  });
});
<|endoftext|>


<commit_before>module.exports = function(cluster) {
    var Promise = require('bluebird');
    function incoming_message(worker, msg) {
        switch(msg.method) {
            case "set":
                cache.set(msg.key, msg.val, msg.ttl, function(err, success) {
                worker.send({
                    sig: msg.method + msg.key,
                    body: {
                        err: err,
                        success: success
                    }
                });
            });
            break;
            case "get":
                cache.get(msg.key, function(err, value) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            value: value
                        }
                    });
            });
            break;
            case "del":
                cache.del(msg.key, function(err, count) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            count: count
                        }
                    });
            });
            break;
            case "ttl":
                cache.del(msg.key, msg.ttl, function(err, changed) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            changed: changed
                        }
                    });
            });
            break;
            case "keys":
                cache.keys(function(err, keys) {
                    worker.send({
                        sig: msg.method,
                        body: {
                            err: err,
                            keys: keys
                        }
                    });
            });
            break;
            case "getStats":
                worker.send({
                    sig: msg.method,
                    body: cache.getStats()
                });
            break;
            case "flushAll":
                worker.send({
                    sig: msg.method,
                    body: cache.flushAll()
                });
            break;
        }
    }
    if(cluster.isMaster) {
        var NodeCache = require("node-cache");
        var cache = new NodeCache();

        cluster.on('online', function(worker) {
            console.log("Cluster cache has been told about " + worker.id);
            worker.on('message', incoming_message.bind(null, worker));
        });
    } else {
        var ClusterCache = {};
        var resolve_dict = {};

        process.on("message", function(msg) {
            if(resolve_dict[msg.sig]) {
                resolve_dict[msg.sig](msg.body);
                delete resolve_dict[msg.sig];
            }
        });

        ClusterCache.set = function(key, val, ttl) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "set",
                    key: key,
                    val: val,
                    ttl: ttl
                });
                resolve_dict["set" + key] = resolve;
            });
        };

        ClusterCache.get = function(key) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "get",
                    key: key,
                });
                resolve_dict["get" + key] = resolve;
            });
        };

        ClusterCache.del = function(key) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "del",
                    key: key,
                });
                resolve_dict["del" + key] = resolve;
            });
        };

        ClusterCache.ttl = function(key, ttl) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "ttl",
                    key: key,
                    ttl: ttl
                });
                resolve_dict["ttl" + key] = resolve;
            });
        };

        ClusterCache.keys = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "keys",
                    ttl: ttl
                });
                resolve_dict.keys = resolve;
            });
        };

        ClusterCache.getStats = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "getStats"
                });
                resolve_dict.getStats = resolve;
            });
        };

        ClusterCache.flushAll = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "flushAll"
                });
                resolve_dict.flushAll = resolve;
            });
        };

        return ClusterCache;
    }
};
<commit_msg>Fixed typo on ttl method<commit_after>module.exports = function(cluster) {
    var Promise = require('bluebird');
    function incoming_message(worker, msg) {
        switch(msg.method) {
            case "set":
                cache.set(msg.key, msg.val, msg.ttl, function(err, success) {
                worker.send({
                    sig: msg.method + msg.key,
                    body: {
                        err: err,
                        success: success
                    }
                });
            });
            break;
            case "get":
                cache.get(msg.key, function(err, value) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            value: value
                        }
                    });
            });
            break;
            case "del":
                cache.del(msg.key, function(err, count) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            count: count
                        }
                    });
            });
            break;
            case "ttl":
                cache.ttl(msg.key, msg.ttl, function(err, changed) {
                    worker.send({
                        sig: msg.method + msg.key,
                        body: {
                            err: err,
                            changed: changed
                        }
                    });
            });
            break;
            case "keys":
                cache.keys(function(err, keys) {
                    worker.send({
                        sig: msg.method,
                        body: {
                            err: err,
                            keys: keys
                        }
                    });
            });
            break;
            case "getStats":
                worker.send({
                    sig: msg.method,
                    body: cache.getStats()
                });
            break;
            case "flushAll":
                worker.send({
                    sig: msg.method,
                    body: cache.flushAll()
                });
            break;
        }
    }
    if(cluster.isMaster) {
        var NodeCache = require("node-cache");
        var cache = new NodeCache();

        cluster.on('online', function(worker) {
            console.log("Cluster cache has been told about " + worker.id);
            worker.on('message', incoming_message.bind(null, worker));
        });
    } else {
        var ClusterCache = {};
        var resolve_dict = {};

        process.on("message", function(msg) {
            if(resolve_dict[msg.sig]) {
                resolve_dict[msg.sig](msg.body);
                delete resolve_dict[msg.sig];
            }
        });

        ClusterCache.set = function(key, val, ttl) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "set",
                    key: key,
                    val: val,
                    ttl: ttl
                });
                resolve_dict["set" + key] = resolve;
            });
        };

        ClusterCache.get = function(key) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "get",
                    key: key,
                });
                resolve_dict["get" + key] = resolve;
            });
        };

        ClusterCache.del = function(key) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "del",
                    key: key,
                });
                resolve_dict["del" + key] = resolve;
            });
        };

        ClusterCache.ttl = function(key, ttl) {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "ttl",
                    key: key,
                    ttl: ttl
                });
                resolve_dict["ttl" + key] = resolve;
            });
        };

        ClusterCache.keys = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "keys",
                    ttl: ttl
                });
                resolve_dict.keys = resolve;
            });
        };

        ClusterCache.getStats = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "getStats"
                });
                resolve_dict.getStats = resolve;
            });
        };

        ClusterCache.flushAll = function() {
            return new Promise(function(resolve, reject) {
                process.send({
                    method: "flushAll"
                });
                resolve_dict.flushAll = resolve;
            });
        };

        return ClusterCache;
    }
};
<|endoftext|>