text: (function () {
  
      'use strict';
  
      angular.module('projectCmdo', ['projectCmdo.components', 'projectCmdo.utils']);
  
      angular.module('projectCmdo.components', []);
      angular.module('projectCmdo.utils', []);
  })();
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo').controller('ProjectCmdoController', ProjectCmdoController);
  
      ProjectCmdoController.$inject = ['_'];
  
      function ProjectCmdoController(_) {
          var cmdo = this;
  
          _.extend(cmdo, {
              name: 'Project Commando'
          });
      }
  })();
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo.utils').factory('_', lodashFactory);
  
      lodashFactory.$inject = ['$window'];
  
      function lodashFactory($window) {
          var _ = $window._;
  
          delete $window._; // remove second Lodash library
  
          return _;
      }
  })();
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo').service('tileService', tileService);
  
      tileService.$inject = ['_'];
  
      function tileService(_) {
  
          this.createTile = function (options) {
              return new TileVM(options);
          };
  
          var TileVM = function () {
              function TileVM(tile) {
                  _classCallCheck(this, TileVM);
  
                  this._tile = {};
  
                  for (var prop in tile) {
                      if (!tile.hasOwnProperty(prop)) {
                          continue;
                      }
                      this[prop] = tile[prop];
                  }
              }
  
              _createClass(TileVM, [{
                  key: '$root',
                  get: function get() {
                      return this._tile.$root || $('');
                  },
                  set: function set($root) {
                      this._tile.$root = $root;
                  }
              }, {
                  key: 'elevation',
                  get: function get() {
                      return this._tile.elevation || 0;
                  },
                  set: function set(elevation) {
                      this._tile.elevation = elevation;
                  }
              }, {
                  key: 'isVisible',
                  get: function get() {
                      return this._tile.isVisible || false;
                  },
                  set: function set(isVisible) {
                      this._tile.isVisible = isVisible;
                  }
              }, {
                  key: 'x',
                  get: function get() {
                      return this._tile.x || 0;
                  },
                  set: function set(x) {
                      this._tile.x = x;
                  }
              }, {
                  key: 'y',
                  get: function get() {
                      return this._tile.y || 0;
                  },
                  set: function set(y) {
                      this._tile.y = y;
                  }
              }]);
  
              return TileVM;
          }();
      }
  })();
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo').factory('tilesFactory', tilesFactory);
  
      tilesFactory.$inject = ['$rootScope', '_', 'tileService'];
  
      function tilesFactory($rootScope, _, tileService) {
          var TilesFactory = function () {
              function TilesFactory(tiles) {
                  _classCallCheck(this, TilesFactory);
  
                  this._tiles = {};
              }
  
              _createClass(TilesFactory, [{
                  key: 'renderTiles',
                  value: function renderTiles(grid) {
                      this.grid = grid;
  
                      if (this.count <= 0) {
                          console.error('Invalid map definition:', this.grid);
                          return;
                      }
  
                      var BEACH = this.grid.x - 2;
                      var JUNGLE = this.grid.x - 3;
                      var OCEAN = this.grid.x - 1;
                      var MIN = 2;
                      var MAX = 5;
                      var elevation = MAX;
                      var peaks = 0;
                      var rows = [];
  
                      for (var rowIndex = 0; rowIndex < this.grid.y; rowIndex++) {
  
                          rows[rowIndex] = [];
  
                          for (var cellIndex = 0; cellIndex < this.grid.x; cellIndex++) {
                              var tile = tileService.createTile({
                                  elevation: _getElevation(cellIndex, rowIndex),
                                  x: cellIndex,
                                  y: rowIndex
                              });
  
                              rows[rowIndex].push(tile);
                          }
  
                          /**
                           * Reset elevation to row's first cell's elevation
                           * so that next row uses its Northern sibling's elevation
                           * to start the calculations for its cells
                           */
                          elevation = rows[rowIndex][0].elevation;
                      }
  
                      this.rows = rows;
  
                      function _getElevation(cell, row) {
                          /**
                           * random cell can be Peak(4)
                           * cell 7 is Beach(1)
                           * cell 8 is Ocean(0)
                           */
  
                          if (cell > JUNGLE) {
                              return cell === BEACH ? 1 : 0;
                          }
  
                          var deltas = [0];
  
                          if (row > 0 && cell > 0) {
                              elevation = Math.floor((rows[row - 1][cell].elevation + rows[row][cell - 1].elevation) / 2);
                          }
  
                          if (elevation > MIN) {
                              deltas.push(-1);
                          }
                          if (elevation < MAX && peaks < 2) {
                              deltas.push(1);
                          }
                          if (elevation < MAX - 2 && peaks < 2) {
                              deltas.push(2);
                              deltas.pop(); // pull off the 0 delta for a greater chance to hit the 2 delta
                          }
  
                          elevation = elevation + _.sample(deltas);
                          peaks = elevation === MAX ? peaks++ : peaks;
  
                          return elevation;
                      }
                  }
              }, {
                  key: 'resetVisibility',
                  value: function resetVisibility() {
                      this.tiles.forEach(function (tile) {
                          tile.isVisible = false;
                      });
                  }
              }, {
                  key: 'toggleVisibility',
                  value: function toggleVisibility(position) {
                      this.userTile = _.find(this.tiles, {
                          x: position.x,
                          y: position.y
                      });
  
                      this.tiles.forEach(_isVisible.bind(this));
  
                      function _isVisible(tile) {
                          var delta = {
                              e: tile.elevation - this.userTile.elevation,
                              x: tile.x - this.userTile.x,
                              y: tile.y - this.userTile.y
                          };
  
                          var isFar = delta.x <= -3 || delta.x >= 3 || delta.y <= -3 || delta.y >= 3; // x/y = -3- || 3+
                          var isHigh = delta.e <= -4 || delta.e >= 2; // e = -4- || 2+
                          var isLow = delta.e <= 2; // e = 2-
                          var isNear = delta.x <= 1 && delta.x >= -1 && delta.y <= 1 && delta.y >= -1; // x/y = -1+ || 1-
  
                          tile.isVisible = !isFar && !isHigh || isNear && isLow;
                      }
                  }
              }, {
                  key: 'count',
                  get: function get() {
                      return this.grid.x * this.grid.y;
                  }
              }, {
                  key: 'grid',
                  get: function get() {
                      return this._tiles.grid || {
                          x: 0,
                          y: 0
                      };
                  },
                  set: function set(grid) {
                      this._tiles.grid = {
                          x: grid && grid.x ? parseInt(grid.x) : 0,
                          y: grid && grid.y ? parseInt(grid.y) : 0
                      };
                  }
              }, {
                  key: 'height',
                  get: function get() {
                      return this._tiles.height || 0;
                  },
                  set: function set(height) {
                      this._tiles.height = height;
                  }
              }, {
                  key: 'rows',
                  get: function get() {
                      return this._tiles.rows || [];
                  },
                  set: function set(rows) {
                      this._tiles.rows = rows;
                  }
              }, {
                  key: 'tiles',
                  get: function get() {
                      return _.flatten(this.rows);
                  }
              }, {
                  key: 'tileSize',
                  get: function get() {
                      return this._tiles.tileSize || 0;
                  },
                  set: function set(tileSize) {
                      this._tiles.tileSize = tileSize;
                  }
              }, {
                  key: 'userTile',
                  get: function get() {
                      return this._tiles.userTile || tileService.createTile();
                  },
                  set: function set(userTile) {
                      this._tiles.userTile = userTile;
                  }
              }, {
                  key: 'width',
                  get: function get() {
                      return this._tiles.width || 0;
                  },
                  set: function set(width) {
                      this._tiles.width = width;
                  }
              }]);
  
              return TilesFactory;
          }();
  
          return new TilesFactory();
      }
  })();
  var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
  
  function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo').factory('userFactory', userFactory);
  
      userFactory.$inject = ['$rootScope', '_'];
  
      function userFactory($rootScope, _) {
  
          var TROOPERCOUNT = 9;
  
          var UserFactory = function () {
              function UserFactory(user) {
                  _classCallCheck(this, UserFactory);
  
                  this._user = {};
  
                  this.createTroopers();
              }
  
              _createClass(UserFactory, [{
                  key: 'createTroopers',
                  value: function createTroopers() {
                      var troopers = [];
                      for (var i = 0; i < TROOPERCOUNT; i++) {
                          troopers.push({
                              health: 3
                          });
                      }
                      this.troopers = troopers;
                  }
              }, {
                  key: 'isSet',
                  get: function get() {
                      return this._user.isSet || false;
                  },
                  set: function set(isSet) {
                      this._user.isSet = isSet;
                  }
              }, {
                  key: 'moves',
                  get: function get() {
                      return this._user.moves || 0;
                  },
                  set: function set(moves) {
                      if (!_.isNumber(moves)) {
                          return;
                      }
  
                      if (moves % 2 === 0 && moves > 3) {
                          this.troopers.pop();
                      }
  
                      this._user.moves = moves;
                  }
              }, {
                  key: 'troopers',
                  get: function get() {
                      return this._user.troopers || [];
                  },
                  set: function set(troopers) {
                      this._user.troopers = troopers;
                  }
              }, {
                  key: 'x',
                  get: function get() {
                      return this._user.x || 0;
                  },
                  set: function set(x) {
                      this._user.x = x;
                  }
              }, {
                  key: 'y',
                  get: function get() {
                      return this._user.y || 0;
                  },
                  set: function set(y) {
                      this._user.y = y;
                  }
              }]);
  
              return UserFactory;
          }();
  
          return new UserFactory();
      }
  })();
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo.components').directive('map', mapDirective);
  
      function mapDirective() {
          var directive = {
              restrict: 'A',
              replace: true,
              templateUrl: 'templates/components/map/map.tmpl.html',
              controller: MapController,
              controllerAs: 'map'
          };
  
          return directive;
      }
  
      MapController.$inject = ['$element', '$rootScope', '$timeout', '_', 'tilesFactory', 'userFactory'];
  
      function MapController($element, $rootScope, $timeout, _, tilesFactory, userFactory) {
  
          var map = this;
  
          _.extend(map, {
              onChangeDimension: onChangeDimension,
              onClickSubmit: onClickSubmit,
              onClickTile: onClickTile,
              onFocusDimension: onFocusDimension,
  
              $cells: [],
              $rows: [],
  
              cols: 12,
              rows: 12,
              tiles: tilesFactory
          });
  
          init();
  
          function init() {
              map.tiles.renderTiles({
                  x: map.cols,
                  y: map.rows
              });
  
              $timeout(initMap);
          }
  
          function initMap() {
              setHeights();
  
              $element.removeClass('map--hidden');
  
              $rootScope.$broadcast('readyMap');
          }
  
          ////
  
          function onChangeDimension() {
              if (map.cols > 16) {
                  console.warn(map.cols + ' Columns? Did you mean "16"?');
                  map.cols = 16;
              }
              if (map.rows > 16) {
                  console.warn(map.rows + ' Rows? Did you mean "16"?');
                  map.rows = 16;
              }
          }
  
          function onClickTile(tile) {
              var deltaX = userFactory.x - tile.x;
              var deltaY = userFactory.y - tile.y;
  
              if (deltaX < -1 || deltaX > 1 || deltaY < -1 || deltaY > 1) {
                  return;
              }
  
              $rootScope.$broadcast('onClickTile', {
                  tile: tile
              });
          }
  
          function onClickSubmit() {
              map.$cells = [];
              map.$rows = [];
  
              map.cols = map.cols > 16 ? 16 : map.cols;
              map.rows = map.rows > 16 ? 16 : map.rows;
  
              $element.addClass('map--hidden');
  
              init();
          }
  
          function onFocusDimension(id) {
              $element.find('#' + id).select();
          }
  
          function setHeights() {
              var _this = this;
  
              map.$rows = $element.find('.map-row');
  
              map.$rows.each(function (index, row) {
                  map.$cells[index] = $(row).find('.map-row__cell');
                  map.$cells[index].each(_setTile.bind(_this, index));
  
                  map.tiles.height = $element.outerHeight();
                  map.tiles.width = $element.outerWidth();
              });
  
              function _setTileSize($cell) {
                  if (!map.tiles.tileSize) {
                      map.tiles.tileSize = $cell.outerWidth();
                  }
  
                  $cell.outerHeight(map.tiles.tileSize);
                  $cell.outerWidth(map.tiles.tileSize);
              }
  
              function _setTile(rowIndex, cellIndex, cell) {
                  _setTileSize($(cell));
  
                  tilesFactory.rows[rowIndex][cellIndex].$root = $(cell);
              }
          }
      }
  })();
  (function () {
  
      'use strict';
  
      angular.module('projectCmdo.components').directive('user', userDirective);
  
      function userDirective() {
          var directive = {
              restrict: 'A',
              replace: true,
              templateUrl: 'templates/components/user/user.tmpl.html',
              controller: UserController,
              controllerAs: 'user'
          };
  
          return directive;
      }
  
      UserController.$inject = ['$element', '$rootScope', '$timeout', '_', 'tilesFactory', 'userFactory'];
  
      function UserController($element, $rootScope, $timeout, _, tilesFactory, userFactory) {
  
          var user = this;
  
          _.extend(user, {
              uf: userFactory
          });
  
          var stopInitListener = $rootScope.$on('readyMap', init);
          var stopTileListener = angular.noop;
  
          function init() {
              stopInitListener();
  
              /** set start position */
              userFactory.x = tilesFactory.grid.x - 2; // starts at the end of the map, on the Beach
              userFactory.y = Math.floor((tilesFactory.grid.y - 1) / 2); // starts halfway down the Beach
  
              setDimensions();
              setPosition();
              setVisibility();
  
              bindEvents();
  
              $rootScope.$broadcast('readyUser');
          }
  
          function bindEvents() {
              userFactory.moves = userFactory.moves + 1;
              userFactory.isSet = true;
  
              stopInitListener = $rootScope.$on('readyMap', reInit);
              stopTileListener = $rootScope.$on('onClickTile', onClickTile);
          }
  
          function onClickTile(event, args) {
              if (userFactory.x === args.tile.x && userFactory.y === args.tile.y) {
                  return;
              }
  
              userFactory.x = args.tile.x;
              userFactory.y = args.tile.y;
  
              reInit();
          }
  
          function reInit() {
              stopInitListener();
              stopTileListener();
  
              userFactory.isSet = false;
  
              $element.outerHeight(0);
              $element.outerWidth(0);
  
              setDimensions();
              setPosition();
              setVisibility();
  
              bindEvents();
          }
  
          function setDimensions() {
              $element.outerHeight(tilesFactory.tileSize);
              $element.outerWidth(tilesFactory.tileSize);
          }
  
          function setPosition() {
              $element.css({
                  top: tilesFactory.tileSize * userFactory.y,
                  left: tilesFactory.tileSize * userFactory.x
              });
          }
  
          function setVisibility() {
              tilesFactory.resetVisibility();
              tilesFactory.toggleVisibility({
                  x: userFactory.x,
                  y: userFactory.y
              });
          }
      }
  })();