<commit_before>(function() {
"use strict";

var cellsize = 24;

var cellType = Object.freeze({
  PASSAGE : "passage",
  WALL : "wall",
  BORDER : "border"
});

var game = {
  lastLoopTime : new Date(),
  elapsedSecs : 0,
  frames : 0,
  lastFrames : 0
};

var player = {
  position : {
    x : 1,
    y : 1
  }
};

var gfx = {
  bricks :     { left: 2,   width: 24 },
  darkbricks : { left: 28,  width: 24 },
  door :       { left: 54,  width: 24 },
  ground :     { left: 80,  width: 24 },
  key :        { left: 106, width: 13 },
  zombie :     { left: 123, width: 16 },
  player :     { left: 142, width: 15 },
  box :        { left: 160, width: 15 },
  getImageFor : function(celltype) {
    switch (celltype) {
      case cellType.PASSAGE: return this.ground;
      case cellType.WALL: return this.bricks;
      case cellType.BORDER: return this.darkbricks;
      default: return this.ground;
    }
  }
};

var maze = {
  width : 30,
  height : 20,
  cells : [],
  getCell : function(x, y) {
    return this.cells[x][y];
  },
  setCell : function(x, y, value) {
    this.cells[x][y] = value;
  },
  init : function() {
    var x = 0, y = 0;
    for (x; x < this.width; x++) {
      this.cells[x] = [];
      y = 0;
      for (y; y < this.height; y++) {
        if (x === 0 || y === 0 || x === this.width - 1 || y === this.height - 1) {
          this.setCell(x, y, cellType.BORDER);
        } else {
          if (x % 2 === 0 && y % 2 === 0) {
            this.setCell(x, y, cellType.WALL);
          } else {
            this.setCell(x, y, cellType.PASSAGE);
          }
        }
      }
    }
  },
  canMoveInto: function(x, y) {
    return this.cells[x][y] === cellType.PASSAGE;
  }
};

var keys = [
  { // left
    ord: 37,
    exec : function() {
      var destX = player.position.x - 1;
      if (maze.canMoveInto(destX, player.position.y)) {
        player.position.x = destX;
      }
    }
  },
  { // up
    ord: 38,
    exec : function() {
      var destY = player.position.y - 1;
      if (maze.canMoveInto(player.position.x, destY)) {
        player.position.y = destY;
      }
    }
  },
  { // right
    ord: 39,
    exec : function() {
      var destX = player.position.x + 1;
      if (maze.canMoveInto(destX, player.position.y)) {
        player.position.x = destX;
      }
    }
  },
  { // down
    ord: 40,
    exec : function() {
      var destY = player.position.y + 1;
      if (maze.canMoveInto(player.position.x, destY)) {
        player.position.y = destY;
      }
    }
  }
];

window.addEventListener("keydown", handleKeyDown);

function handleKeyDown(event) {
  keys.forEach(function(key, index, array) {
    if (event.which === key.ord) {
      key.exec();
    }
  });
}

var canvasGame = document.getElementById("maingame"),
  contextGame = canvasGame.getContext("2d"),
  requestAnimFrame = window.requestAnimationFrame,
  imgSprites = new Image();
imgSprites.src = "images/sprites.png";
imgSprites.onload = init;

function init() {
  maze.init();
  requestAnimFrame(gameLoop);
  console.log("initialized");
}

function gameLoop() {
  document.getElementById("score").innerHTML = "
Score: " + game.elapsedSecs.toString() + "
";
  contextGame.clearRect(0, 0, canvasGame.width, canvasGame.height);
  paintMaze();
  paintImage(gfx.player, player.position.x * cellsize, player.position.y * cellsize);
  paintElapsedTime();
  requestAnimFrame(gameLoop);
}

function paintMaze() {
  var x = 0, y;
  for (x; x < maze.width; x++) {
    y = 0;
    for (y; y < maze.height; y++) {
      paintImage(gfx.getImageFor(maze.getCell(x, y)), x * cellsize, y * cellsize);
    }
  }
}

function paintElapsedTime() {
  var tickTime = new Date();
  if ((tickTime - game.lastLoopTime) > 1000) {
    game.lastFrames = game.frames;
    game.frames = 0;
    game.lastLoopTime = tickTime;
    game.elapsedSecs++;
  }
  game.frames++;
  contextGame.font = "30px Verdana";
  contextGame.fillText(game.elapsedSecs.toString(), cellsize, canvasGame.height - cellsize);
  contextGame.font = "15px Verdana";
  contextGame.fillText(game.lastFrames.toString(), cellsize, canvasGame.height - 50);
}

function paintImage(sprite, x, y) {
  contextGame.drawImage(imgSprites, sprite.left, 2, sprite.width, cellsize, x, y, sprite.width, cellsize);
}

}());
<commit_msg>added a door;<commit_after>(function() {
"use strict";

var cellsize = 24;

var cellType = Object.freeze({
  PASSAGE : "passage",
  WALL : "wall",
  BORDER : "border",
  DOOR : "door"
});

var game = {
  lastLoopTime : new Date(),
  elapsedSecs : 0,
  frames : 0,
  lastFrames : 0
};

var player = {
  position : {
    x : 1,
    y : 1
  }
};

var gfx = {
  bricks :     { left: 2,   width: 24 },
  darkbricks : { left: 28,  width: 24 },
  door :       { left: 54,  width: 24 },
  ground :     { left: 80,  width: 24 },
  key :        { left: 106, width: 13 },
  zombie :     { left: 123, width: 16 },
  player :     { left: 142, width: 15 },
  box :        { left: 160, width: 15 },
  getImageFor : function(celltype) {
    switch (celltype) {
      case cellType.PASSAGE: return this.ground;
      case cellType.WALL: return this.bricks;
      case cellType.BORDER: return this.darkbricks;
      case cellType.DOOR: return this.door;
      default: return this.ground;
    }
  }
};

var maze = {
  width : 30,
  height : 20,
  cells : [],
  getCell : function(x, y) {
    return this.cells[x][y];
  },
  setCell : function(x, y, value) {
    this.cells[x][y] = value;
  },
  init : function() {
    var x = 0, y = 0;
    for (x; x < this.width; x++) {
      this.cells[x] = [];
      y = 0;
      for (y; y < this.height; y++) {
        if (x === 0 || y === 0 || x === this.width - 1 || y === this.height - 1) {
          this.setCell(x, y, cellType.BORDER);
        } else {
          if (x % 2 === 0 && y % 2 === 0) {
            this.setCell(x, y, cellType.WALL);
          } else {
            this.setCell(x, y, cellType.PASSAGE);
          }
        }
      }
    };
    this.cells[0][1] = cellType.DOOR;
  },
  canMoveInto: function(x, y) {
    return this.cells[x][y] === cellType.PASSAGE;
  }
};

var keys = [
  { // left
    ord: 37,
    exec : function() {
      var destX = player.position.x - 1;
      if (maze.canMoveInto(destX, player.position.y)) {
        player.position.x = destX;
      }
    }
  },
  { // up
    ord: 38,
    exec : function() {
      var destY = player.position.y - 1;
      if (maze.canMoveInto(player.position.x, destY)) {
        player.position.y = destY;
      }
    }
  },
  { // right
    ord: 39,
    exec : function() {
      var destX = player.position.x + 1;
      if (maze.canMoveInto(destX, player.position.y)) {
        player.position.x = destX;
      }
    }
  },
  { // down
    ord: 40,
    exec : function() {
      var destY = player.position.y + 1;
      if (maze.canMoveInto(player.position.x, destY)) {
        player.position.y = destY;
      }
    }
  }
];

window.addEventListener("keydown", handleKeyDown);

function handleKeyDown(event) {
  keys.forEach(function(key, index, array) {
    if (event.which === key.ord) {
      key.exec();
    }
  });
}

var canvasGame = document.getElementById("maingame"),
  contextGame = canvasGame.getContext("2d"),
  requestAnimFrame = window.requestAnimationFrame,
  imgSprites = new Image();
imgSprites.src = "images/sprites.png";
imgSprites.onload = init;

function init() {
  maze.init();
  requestAnimFrame(gameLoop);
  console.log("initialized");
}

function gameLoop() {
  document.getElementById("score").innerHTML = "
Score: " + game.elapsedSecs.toString() + "
";
  contextGame.clearRect(0, 0, canvasGame.width, canvasGame.height);
  paintMaze();
  paintImage(gfx.player, player.position.x * cellsize, player.position.y * cellsize);
  paintElapsedTime();
  requestAnimFrame(gameLoop);
}

function paintMaze() {
  var x = 0, y;
  for (x; x < maze.width; x++) {
    y = 0;
    for (y; y < maze.height; y++) {
      paintImage(gfx.getImageFor(maze.getCell(x, y)), x * cellsize, y * cellsize);
    }
  }
}

function paintElapsedTime() {
  var tickTime = new Date();
  if ((tickTime - game.lastLoopTime) > 1000) {
    game.lastFrames = game.frames;
    game.frames = 0;
    game.lastLoopTime = tickTime;
    game.elapsedSecs++;
  }
  game.frames++;
  contextGame.font = "30px Verdana";
  contextGame.fillText(game.elapsedSecs.toString(), cellsize, canvasGame.height - cellsize);
  contextGame.font = "15px Verdana";
  contextGame.fillText(game.lastFrames.toString(), cellsize, canvasGame.height - 50);
}

function paintImage(sprite, x, y) {
  contextGame.drawImage(imgSprites, sprite.left, 2, sprite.width, cellsize, x, y, sprite.width, cellsize);
}

}());
<|endoftext|>


<commit_before>Template.animeExplore.created = function() {

	// Initialize reactive variables
	this.loaded = new ReactiveVar(0);
	this.limit = new ReactiveVar(24);
	this.ready = new ReactiveVar(false);
	this.filterObject = new ReactiveVar({});
	this.sortObject = new ReactiveVar({canonicalTitle: 1});

	// Display purposes
	this.dateCurrentlyActive = new ReactiveVar("None");

	var self = this;

	this.autorun(function() {
		var limit = self.limit.get();
		var filterObject = self.filterObject.get();
		var sortObject = self.sortObject.get();

		console.log("Asking for " + limit + " activities");

		var subscription = Meteor.subscribe('animeExplore', limit, filterObject, sortObject);

		// We wait until we've got the subscription to be ready
		if (subscription.ready()) {
			self.loaded.set(limit);
			self.ready.set(true);
		} else {
			self.ready.set(false);
		}
	});

	// This will be our activity cursor
	this.anime = function() {
		return Anime.find(self.filterObject.get(), {sort: self.sortObject.get(), limit: self.loaded.get()});
	}

}

Template.animeExplore.rendered = function() {
	// Initialize the selectize plugin
	var self = this;

	Meteor.call('getGenres', function(error, result) {
		if (!error) {
			$("#selectGenre").selectize({
				valueField: "name",
				labelField: "name",
				searchField: "name",
				options: result,
				create: false,
				onChange: function(value) {
					var filterObject = self.filterObject.get();

					if (!value) {
						if (filterObject.genres) {
							delete filterObject.genres;
						}
					} else {
						filterObject.genres = {
							$all: value
						};
					}

					self.filterObject.set(filterObject);
				}
			});
		}
	});

}

Template.animeExplore.events({
	'click #loadMore' : function(event, template) {

		var limit = template.limit.get();
		var increment = 18;

		console.log('Clicked');
		// Let's increment limit by our increment amount, so we can grab the next amount of activities
		template.limit.set(limit + increment);
	},
	'click #upcomingAnime' : function(event, template) {
		// Upcoming anime should have their start date be greater than today's date
		var filterObject = template.filterObject.get();

		// We'll remove the $or because it's for currently airing
		if (filterObject.$or)
			delete filterObject.$or;

		filterObject.startDate = {
			$gte: new Date()
		};

		template.dateCurrentlyActive.set("Upcoming");

		template.filterObject.set(filterObject);
	},
	'click #currentlyAiring' : function(event, template) {
		// Currently airing anime would either not have endDate field or it's value will be greater than
		// today's date
		var filterObject = template.filterObject.get();
		// We'll have to remove any other date conditions on here first
		if (filterObject.startDate)
			delete filterObject.startDate;

		filterObject.$or = [{
			endDate: {$gte: new Date()}
		},
		{
			endDate: {$exists: false}
		}]

		template.dateCurrentlyActive.set("Currently Airing");
		template.filterObject.set(filterObject);
	},
	'click #noneDate' : function(event, template) {
		// This method essentially resets and date restrictions we had
		// like upcoming or currentlyAiring
		var filterObject = template.filterObject.get();

		if (filterObject.startDate)
			delete filterObject.startDate;

		if (filterObject.$or)
			delete filterObject.$or

		template.dateCurrentlyActive.set("None");
		template.filterObject.set(filterObject);
	}
});

Template.animeExplore.helpers({

	anime: function() {
		return Template.instance().anime();
	},
	isReady: function() {
		return Template.instance().ready.get();
	},
	hasMoreAnime: function() {
		return Template.instance().anime().count() >= Template.instance().limit.get();
	},
	dateCurrentlyActive: function(type) {
		if (type === Template.instance().dateCurrentlyActive.get()) {
			return 'active';
		} else {
			return '';
		}
	}
});<commit_msg>Fixed a bug with the currently airing query<commit_after>Template.animeExplore.created = function() {

	// Initialize reactive variables
	this.loaded = new ReactiveVar(0);
	this.limit = new ReactiveVar(24);
	this.ready = new ReactiveVar(false);
	this.filterObject = new ReactiveVar({});
	this.sortObject = new ReactiveVar({canonicalTitle: 1});

	// Display purposes
	this.dateCurrentlyActive = new ReactiveVar("None");

	var self = this;

	this.autorun(function() {
		var limit = self.limit.get();
		var filterObject = self.filterObject.get();
		var sortObject = self.sortObject.get();

		console.log("Asking for " + limit + " activities");

		var subscription = Meteor.subscribe('animeExplore', limit, filterObject, sortObject);

		// We wait until we've got the subscription to be ready
		if (subscription.ready()) {
			self.loaded.set(limit);
			self.ready.set(true);
		} else {
			self.ready.set(false);
		}
	});

	// This will be our activity cursor
	this.anime = function() {
		return Anime.find(self.filterObject.get(), {sort: self.sortObject.get(), limit: self.loaded.get()});
	}

}

Template.animeExplore.rendered = function() {
	// Initialize the selectize plugin
	var self = this;

	Meteor.call('getGenres', function(error, result) {
		if (!error) {
			$("#selectGenre").selectize({
				valueField: "name",
				labelField: "name",
				searchField: "name",
				options: result,
				create: false,
				onChange: function(value) {
					var filterObject = self.filterObject.get();

					if (!value) {
						if (filterObject.genres) {
							delete filterObject.genres;
						}
					} else {
						filterObject.genres = {
							$all: value
						};
					}

					self.filterObject.set(filterObject);
				}
			});
		}
	});

}

Template.animeExplore.events({
	'click #loadMore' : function(event, template) {

		var limit = template.limit.get();
		var increment = 18;

		console.log('Clicked');
		// Let's increment limit by our increment amount, so we can grab the next amount of activities
		template.limit.set(limit + increment);
	},
	'click #upcomingAnime' : function(event, template) {
		// Upcoming anime should have their start date be greater than today's date
		var filterObject = template.filterObject.get();

		// We'll remove the $or because it's for currently airing
		if (filterObject.$and)
			delete filterObject.$and;

		filterObject.startDate = {
			$gte: new Date()
		};

		template.dateCurrentlyActive.set("Upcoming");

		template.filterObject.set(filterObject);
	},
	'click #currentlyAiring' : function(event, template) {
		// Currently airing anime would either not have endDate field or it's value will be greater than
		// today's date and will have their start date before today's value
		var filterObject = template.filterObject.get();
		// We'll have to remove any other date conditions on here first
		if (filterObject.startDate)
			delete filterObject.startDate;

		filterObject.$and = [{
			$or: [{
				endDate: {$gte: new Date()}
			},
			{
				endDate: {$exists: false}
			}]
		},
		{
			startDate: {
				$lt: new Date()
			}
		}];

		template.dateCurrentlyActive.set("Currently Airing");
		template.filterObject.set(filterObject);
	},
	'click #noneDate' : function(event, template) {
		// This method essentially resets and date restrictions we had
		// like upcoming or currentlyAiring
		var filterObject = template.filterObject.get();

		if (filterObject.startDate)
			delete filterObject.startDate;

		if (filterObject.$and)
			delete filterObject.$and;

		template.dateCurrentlyActive.set("None");
		template.filterObject.set(filterObject);
	}
});

Template.animeExplore.helpers({

	anime: function() {
		return Template.instance().anime();
	},
	isReady: function() {
		return Template.instance().ready.get();
	},
	hasMoreAnime: function() {
		return Template.instance().anime().count() >= Template.instance().limit.get();
	},
	dateCurrentlyActive: function(type) {
		if (type === Template.instance().dateCurrentlyActive.get()) {
			return 'active';
		} else {
			return '';
		}
	}
});<|endoftext|>


<commit_before>const keystone	= require( 'keystone' );
const Types		= keystone.Field.Types;

// Create model. Additional options allow menu name to be used what auto-generating URLs
var MediaFeature = new keystone.List( 'Media Feature' );

// Create fields
MediaFeature.add( 'Media Feature', {

	source: { type: Types.Relationship, label: 'source', ref: 'Source', filters: { isActive: true }, required: true, initial: true },
	date: { type: Types.Date, label: 'date', format: 'MM/DD/YYYY', required: true, initial: true },
	notes: { type: Types.Textarea, label: 'notes', initial: true },
	children: { type: Types.Relationship, label: 'children', ref: 'Child', many: true, initial: true }

});

// Define default columns in the admin interface and register the model
MediaFeature.defaultColumns = 'child, source, date, notes';
MediaFeature.register();<commit_msg>#23 | update default sort order for media features<commit_after>const keystone	= require( 'keystone' );
const Types		= keystone.Field.Types;

// Create model. Additional options allow menu name to be used what auto-generating URLs
var MediaFeature = new keystone.List( 'Media Feature', {
	defaultSort: '-date'
});

// Create fields
MediaFeature.add( 'Media Feature', {

	source: { type: Types.Relationship, label: 'source', ref: 'Source', filters: { isActive: true }, required: true, initial: true },
	date: { type: Types.Date, label: 'date', format: 'MM/DD/YYYY', required: true, initial: true },
	notes: { type: Types.Textarea, label: 'notes', initial: true },
	children: { type: Types.Relationship, label: 'children', ref: 'Child', many: true, initial: true }

});

// Define default columns in the admin interface and register the model
MediaFeature.defaultColumns = 'child, source, date, notes';
MediaFeature.register();<|endoftext|>


<commit_before>
const path = require("path");
const fs = require("fs-extra");
const replaceExt = require("replace-ext");

function html() {
  return fs.readdirSync(path.join(__dirname, "compilations"))
    .map(file => `- {.link ${path.join("compilations", file)} | ${replaceExt(file, "")}}`)
    .join("\n");
}

module.exports = html;
<commit_msg>Update compilation list time format<commit_after>
"use strict";

const path = require("path");
const fs = require("fs-extra");
const replaceExt = require("replace-ext");

function getTimestamp(str) {
  let parts = str.split("-");
  let len = parts.length;
  if (len >= 3 && len <= 5) {
    let date = [parts[0], parts[1], parts[2]].join("/");
    if (len >= 4) {
      date += ` ${parts.slice(3).join(":")} pm`;
    }
    return date;
  }
  return str;
}

function html() {
  return fs.readdirSync(path.join(__dirname, "compilations"))
    .map(file => `- {.link ${path.join("compilations", file)} | ${getTimestamp(replaceExt(file, ""))}}`)
    .join("\n");
}

module.exports = html;
<|endoftext|>


<commit_before>'use strict';

const app = require('koa')();
const router = require('koa-joi-router');
const docs = require('../');

// Temporary fix for koa-joi-router only accepting routes one at a time
const createRouter = route => {
   const rtr = router();
   [].concat(route || []).forEach(it => rtr.route(it));
   return rtr;
};

// Create the routers for various resources
const petRouter = createRouter( require('./routes/pets') );
const storeRouter = createRouter( require('./routes/store') );

// Add the routes to the koa server
app.use(petRouter.middleware());
app.use(storeRouter.middleware());

// Setup a path for hosting the documentation
app.use(docs.get('/v1/docs', {
   title: 'Pet Store API',    // Add page title and other info
   version: '1.0.0',

   theme: 'simplex',            // Any theme from www.bootswatch.com

   groups: [
      // Provide the routes to the koa-api-docs for rendering
      {
         groupName: 'Pets',
         routes: petRouter.routes,
         description: 'Functionality for dealing with pets',
         extendedDescription: `
            Markdown is supported in the \`extendedDescription\` fields so
            it is an ideal place to add additional information while leaving
            the \`friendlyName\` and \`description\` fields concise. This allows
            easier navigation and better collapsing of groups and routes.

            * Donec et mollis dolor.
            * Praesent et diam eget libero egestas mattis sit amet vitae augue.
            * Nam tincidunt congue enim, ut porta lorem lacinia consectetur.
            * Donec ut libero sed arcu vehicula ultricies a non tortor.
            * Lorem ipsum dolor sit amet, consectetur adipiscing elit.
         `
      },
      { groupName: 'Store', routes: storeRouter.routes }
   ]
}));

app.listen(3000, (err) => {
   if (err) throw err;
   console.log(`Docs are available at http://localhost:3000/v1/docs`);
});
<commit_msg>Update example<commit_after>'use strict';

const app = require('koa')();
const router = require('koa-joi-router');
const docs = require('../');

// Temporary fix for koa-joi-router only accepting routes one at a time
const createRouter = route => {
   const rtr = router();
   [].concat(route || []).forEach(it => rtr.route(it));
   return rtr;
};

// Create the routers for various resources
const petRouter = createRouter( require('./routes/pets') );
const storeRouter = createRouter( require('./routes/store') );

// Add the routes to the koa server
app.use(petRouter.middleware());
app.use(storeRouter.middleware());

// Setup a path for hosting the documentation
app.use(docs.get('/docs', {
   title: 'Pet Store API',    // Add page title and other info
   version: '1.0.0',

   theme: 'paper',            // Any theme from www.bootswatch.com

   groups: [
      // Provide the routes to the koa-api-docs for rendering
      {
         groupName: 'Pets',
         routes: petRouter.routes,
         description: 'Functionality for dealing with pets',
         extendedDescription: `
            Markdown is supported in the \`extendedDescription\` fields so
            it is an ideal place to add additional information while leaving
            the \`friendlyName\` and \`description\` fields concise. This allows
            easier navigation and better collapsing of groups and routes.

            * Donec et mollis dolor.
            * Praesent et diam eget libero egestas mattis sit amet vitae augue.
            * Nam tincidunt congue enim, ut porta lorem lacinia consectetur.
            * Donec ut libero sed arcu vehicula ultricies a non tortor.
            * Lorem ipsum dolor sit amet, consectetur adipiscing elit.
         `
      },
      { groupName: 'Store', routes: storeRouter.routes }
   ]
}));

app.listen(3000, (err) => {
   if (err) throw err;
   console.log(`Docs are available at http://localhost:3000/v1/docs`);
});
<|endoftext|>


<commit_before>const http  = require('http')
    , bogan = require('boganipsum')
    , words = [
          bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
        , bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
        , bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
      ]

function writeWords(i, delay, res) {
  words[i].forEach(function (w) { res.write(w + ' ') })
  res.end()
}

function server (i, delay, port) {
  return http.createServer(function (req, res) {
    writeWords(i, delay, res)
  }).listen(port)
}

module.exports = function () {
  var servers = [
      server(0, 100, 9345)
    , server(1, 0,   9346)
    , server(2, 50,  9347)
  ]

  return {
      args  : [
          'http://localhost:9345'
        , 'http://localhost:9346'
        , 'http://localhost:9347'
      ]
    , stdin : null
    , long  : true
    , close : function () {
        servers.forEach(function (server) {
          server.close()
        })
      }
  }
}<commit_msg>fix delay in juggling-async exercise<commit_after>const http  = require('http')
    , bogan = require('boganipsum')
    , words = [
          bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
        , bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
        , bogan({ paragraphs: 1, sentenceMax: 1 }).split(' ')
      ]

function writeWords(i, delay, res) {
  setTimeout(function () {
    words[i].forEach(function (w) { res.write(w + ' ') })
    res.end()
  }, delay)
}

function server (i, delay, port) {
  return http.createServer(function (req, res) {
    writeWords(i, delay, res)
  }).listen(port)
}

module.exports = function () {
  var servers = [
      server(0, 100, 9345)
    , server(1, 0,   9346)
    , server(2, 50,  9347)
  ]

  return {
      args  : [
          'http://localhost:9345'
        , 'http://localhost:9346'
        , 'http://localhost:9347'
      ]
    , stdin : null
    , long  : true
    , close : function () {
        servers.forEach(function (server) {
          server.close()
        })
      }
  }
}<|endoftext|>


<commit_before>(function() {
  'use strict';

  angular.module('foundation.modal', ['foundation.core'])
    .directive('zfModal', modalDirective)
    .factory('ModalFactory', ModalFactory)
  ;

  FoundationModal.$inject = ['FoundationApi', 'ModalFactory'];

  function FoundationModal(foundationApi, ModalFactory) {
    var service    = {};

    service.activate = activate;
    service.deactivate = deactivate;
    service.newModal = newModal;

    return service;

    //target should be element ID
    function activate(target) {
      foundationApi.publish(target, 'show');
    }

    //target should be element ID
    function deactivate(target) {
      foundationApi.publish(target, 'hide');
    }

    //new modal has to be controlled via the new instance
    function newModal(config) {
      return new ModalFactory(config);
    }
  }

  modalDirective.$inject = ['FoundationApi'];

  function modalDirective(foundationApi) {

    var directive = {
      restrict: 'EA',
      templateUrl: 'components/modal/modal.html',
      transclude: true,
      scope: true,
      replace: true,
      compile: compile
    };

    return directive;

    function compile(tElement, tAttrs, transclude) {
      var type = 'modal';

      return {
        pre: preLink,
        post: postLink
      };

      function preLink(scope, iElement, iAttrs, controller) {
          iAttrs.$set('zf-closable', type);
      }

      function postLink(scope, element, attrs) {
        var dialog = angular.element(element.children()[0]);

        scope.active = scope.active || false;
        scope.overlay = attrs.overlay === 'false' ? false : true;
        scope.overlayClose = attrs.overlayClose === 'false' ? false : true;

        var animationIn = attrs.animationIn || 'fadeIn';
        var animationOut = attrs.animationOut || 'fadeOut';

        var overlayIn = 'fadeIn';
        var overlayOut = 'fadeOut';

        scope.hideOverlay = function() {
          if(scope.overlayClose) {
            scope.hide();
          }
        };

        scope.hide = function() {
          scope.active = false;
          animate();
          return;
        };

        scope.show = function() {
          scope.active = true;
          animate();
          dialog.tabIndex = -1;
          dialog[0].focus();
          return;
        };

        scope.toggle = function() {
          scope.active = !scope.active;
          animate();
          return;
        };

        init();

        //setup
        foundationApi.subscribe(attrs.id, function(msg) {
          if(msg === 'show' || msg === 'open') {
            scope.show();
          } else if (msg === 'close' || msg === 'hide') {
            scope.hide();
          } else if (msg === 'toggle') {
            scope.toggle();
          }

          if (scope.$root && !scope.$root.$$phase) {
            scope.$apply();
          }

          return;
        });

        function animate() {
          //animate both overlay and dialog
          if(!scope.overlay) {
            element.css('background', 'transparent');
          }

          foundationApi.animate(element, scope.active, overlayIn, overlayOut);
          foundationApi.animate(dialog, scope.active, animationIn, animationOut);
        }

        function init() {
          if(scope.active) {
            scope.show();
          }
        }
      }
    }
  }

  ModalFactory.$inject = ['$http', '$templateCache', '$rootScope', '$compile', '$timeout', '$q', 'FoundationApi'];

  function ModalFactory($http, $templateCache, $rootScope, $compile, $timeout, $q, foundationApi) {
    return modalFactory;

    function modalFactory(config) {
      var self = this, //for prototype functions
          container = angular.element(config.container || document.body),
          id = config.id || foundationApi.generateUuid(),
          attached = false,
          destroyed = false,
          html,
          element,
          fetched,
          scope,
          contentScope
      ;

      var props = [
        'animationIn',
        'animationOut',
        'overlay',
        'overlayClose'
      ];

      if(config.templateUrl) {
        //get template
        fetched = $http.get(config.templateUrl, {
          cache: $templateCache
        }).then(function (response) {
          html = response.data;
          assembleDirective();
        });

      } else if(config.template) {
        //use provided template
        fetched = true;
        html = config.template;
        assembleDirective();
      }

      self.activate = activate;
      self.deactivate = deactivate;
      self.toggle = toggle;
      self.destroy = destroy;

      return {
        activate: activate,
        deactivate: deactivate,
        toggle: toggle,
        destroy: destroy
      };

      function checkStatus() {
        if(destroyed) {
          throw "Error: Modal was destroyed. Delete the object and create a new ModalFactory instance."
        }
      }

      function activate() {
        checkStatus();
        $timeout(function() {
          init(true);
          foundationApi.publish(id, 'show');
        }, 0, false);
      }

      function deactivate() {
        checkStatus();
        $timeout(function() {
          init(false);
          foundationApi.publish(id, 'hide');
        }, 0, false);
      }

      function toggle() {
        checkStatus();
        $timeout(function() {
          init(true);
          foundationApi.publish(id, 'toggle');
        }, 0, false);
      }

      function init(state) {
        $q.when(fetched).then(function() {
          if(!attached && html.length > 0) {
            var modalEl = container.append(element);

            scope.active = state;
            $compile(element)(scope);

            attached = true;
          }
        });
      }

      function assembleDirective() {
        // check for duplicate elements to prevent factory from cloning modals
        if (document.getElementById(id)) {
          return;
        }

        html = '<zf-modal id="' + id + '">' + html + '</zf-modal>';

        element = angular.element(html);

        scope = $rootScope.$new();

        // account for directive attributes
        for(var i = 0; i < props.length; i++) {
          var prop = props[i];

          if(config[prop]) {
            switch (prop) {
              case 'animationIn':
                element.attr('animation-in', config[prop]);
                break;
              case 'animationOut':
                element.attr('animation-out', config[prop]);
                break;
              default:
                element.attr(prop, config[prop]);
            }
          }
        }
        // access view scope variables
        if (config.contentScope) {
          contentScope = config.contentScope;
          for (var prop in config.contentScope) {
            if (config.contentScope.hasOwnProperty(prop)) {
              scope[prop] = config.contentScope[prop];
            }
          }
        }
      }

      function destroy() {
        self.deactivate();
        setTimeout(function() {
          scope.$destroy();
          element.remove();
          destroyed = true;
        }, 3000);
        foundationApi.unsubscribe(id);
      }

    }

  }

})();
<commit_msg>Allow ModalFactory to create dialog modals<commit_after>(function() {
  'use strict';

  angular.module('foundation.modal', ['foundation.core'])
    .directive('zfModal', modalDirective)
    .factory('ModalFactory', ModalFactory)
  ;

  FoundationModal.$inject = ['FoundationApi', 'ModalFactory'];

  function FoundationModal(foundationApi, ModalFactory) {
    var service    = {};

    service.activate = activate;
    service.deactivate = deactivate;
    service.newModal = newModal;

    return service;

    //target should be element ID
    function activate(target) {
      foundationApi.publish(target, 'show');
    }

    //target should be element ID
    function deactivate(target) {
      foundationApi.publish(target, 'hide');
    }

    //new modal has to be controlled via the new instance
    function newModal(config) {
      return new ModalFactory(config);
    }
  }

  modalDirective.$inject = ['FoundationApi'];

  function modalDirective(foundationApi) {

    var directive = {
      restrict: 'EA',
      templateUrl: 'components/modal/modal.html',
      transclude: true,
      scope: true,
      replace: true,
      compile: compile
    };

    return directive;

    function compile(tElement, tAttrs, transclude) {
      var type = 'modal';

      return {
        pre: preLink,
        post: postLink
      };

      function preLink(scope, iElement, iAttrs, controller) {
          iAttrs.$set('zf-closable', type);
      }

      function postLink(scope, element, attrs) {
        var dialog = angular.element(element.children()[0]);

        scope.active = scope.active || false;
        scope.overlay = attrs.overlay === 'false' ? false : true;
        scope.overlayClose = attrs.overlayClose === 'false' ? false : true;

        var animationIn = attrs.animationIn || 'fadeIn';
        var animationOut = attrs.animationOut || 'fadeOut';

        var overlayIn = 'fadeIn';
        var overlayOut = 'fadeOut';

        scope.hideOverlay = function() {
          if(scope.overlayClose) {
            scope.hide();
          }
        };

        scope.hide = function() {
          scope.active = false;
          animate();
          return;
        };

        scope.show = function() {
          scope.active = true;
          animate();
          dialog.tabIndex = -1;
          dialog[0].focus();
          return;
        };

        scope.toggle = function() {
          scope.active = !scope.active;
          animate();
          return;
        };

        init();

        //setup
        foundationApi.subscribe(attrs.id, function(msg) {
          if(msg === 'show' || msg === 'open') {
            scope.show();
          } else if (msg === 'close' || msg === 'hide') {
            scope.hide();
          } else if (msg === 'toggle') {
            scope.toggle();
          }

          if (scope.$root && !scope.$root.$$phase) {
            scope.$apply();
          }

          return;
        });

        function animate() {
          //animate both overlay and dialog
          if(!scope.overlay) {
            element.css('background', 'transparent');
          }

          foundationApi.animate(element, scope.active, overlayIn, overlayOut);
          foundationApi.animate(dialog, scope.active, animationIn, animationOut);
        }

        function init() {
          if(scope.active) {
            scope.show();
          }
        }
      }
    }
  }

  ModalFactory.$inject = ['$http', '$templateCache', '$rootScope', '$compile', '$timeout', '$q', 'FoundationApi'];

  function ModalFactory($http, $templateCache, $rootScope, $compile, $timeout, $q, foundationApi) {
    return modalFactory;

    function modalFactory(config) {
      var self = this, //for prototype functions
          container = angular.element(config.container || document.body),
          id = config.id || foundationApi.generateUuid(),
          attached = false,
          destroyed = false,
          html,
          element,
          fetched,
          scope,
          contentScope
      ;

      var props = [
        'animationIn',
        'animationOut',
        'overlay',
        'overlayClose',
        'dialog'
      ];

      if(config.templateUrl) {
        //get template
        fetched = $http.get(config.templateUrl, {
          cache: $templateCache
        }).then(function (response) {
          html = response.data;
          assembleDirective();
        });

      } else if(config.template) {
        //use provided template
        fetched = true;
        html = config.template;
        assembleDirective();
      }

      self.activate = activate;
      self.deactivate = deactivate;
      self.toggle = toggle;
      self.destroy = destroy;

      return {
        activate: activate,
        deactivate: deactivate,
        toggle: toggle,
        destroy: destroy
      };

      function checkStatus() {
        if(destroyed) {
          throw "Error: Modal was destroyed. Delete the object and create a new ModalFactory instance."
        }
      }

      function activate() {
        checkStatus();
        $timeout(function() {
          init(true);
          foundationApi.publish(id, 'show');
        }, 0, false);
      }

      function deactivate() {
        checkStatus();
        $timeout(function() {
          init(false);
          foundationApi.publish(id, 'hide');
        }, 0, false);
      }

      function toggle() {
        checkStatus();
        $timeout(function() {
          init(true);
          foundationApi.publish(id, 'toggle');
        }, 0, false);
      }

      function init(state) {
        $q.when(fetched).then(function() {
          if(!attached && html.length > 0) {
            var modalEl = container.append(element);

            scope.active = state;
            $compile(element)(scope);

            attached = true;
          }
        });
      }

      function assembleDirective() {
        // check for duplicate elements to prevent factory from cloning modals
        if (document.getElementById(id)) {
          return;
        }

        html = '<zf-modal id="' + id + '">' + html + '</zf-modal>';

        element = angular.element(html);

        scope = $rootScope.$new();

        // account for directive attributes and modal classes
        for(var i = 0; i < props.length; i++) {
          var prop = props[i];

          if(config[prop]) {
            switch (prop) {
              case 'animationIn':
                element.attr('animation-in', config[prop]);
                break;
              case 'animationOut':
                element.attr('animation-out', config[prop]);
                break;
              case 'dialog':
                element.addClass('dialog');
                break;
              default:
                element.attr(prop, config[prop]);
            }
          }
        }
        // access view scope variables
        if (config.contentScope) {
          contentScope = config.contentScope;
          for (var prop in config.contentScope) {
            if (config.contentScope.hasOwnProperty(prop)) {
              scope[prop] = config.contentScope[prop];
            }
          }
        }
      }

      function destroy() {
        self.deactivate();
        setTimeout(function() {
          scope.$destroy();
          element.remove();
          destroyed = true;
        }, 3000);
        foundationApi.unsubscribe(id);
      }

    }

  }

})();
<|endoftext|>


<commit_before>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2012, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

// [WIP]

define(function(require, exports, module) {
"use strict";
var TokenIterator = require("../token_iterator").TokenIterator;

function is(token, type) {
    return token.type.lastIndexOf(type + ".xml") > -1;
}

// do not indent after singleton tags or <html>
exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", "html", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];

// insert a line break after block level tags
exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"];

exports.beautify = function(session) {
    var iterator = new TokenIterator(session, 0, 0);
    var token = iterator.getCurrentToken();
    var tabString = session.getTabString();
    var singletonTags = exports.singletonTags;
    var blockTags = exports.blockTags;
    var nextToken;
    var breakBefore = false;
    var spaceBefore = false;
    var spaceAfter = false;
    var code = "";
    var value = "";
    var tagName = "";
    var indent = 0;
    var inBlock = false;
    var inCase = false;
    var onCaseLine = false;
    var row;
    var curRow = 0;
    var rowsToAdd = 0;
    var rowTokens = [];
    var abort = false;
    var i;
    var indentNextLine = false;
    var inCSS = false;

    var trimNext = function() {
        if (nextToken && nextToken.value)
            nextToken.value = nextToken.value.trim();
    };

    while (token !== null) {
        curRow = iterator.getCurrentTokenRow();
        rowTokens = iterator.$rowTokens;
        nextToken = iterator.stepForward();

        if (typeof token !== "undefined") {
            value = token.value;

            // mode
            inCSS = (tagName === "style" || session.$modeId === "ace/mode/css");

            // are we in a block tag
            if (is(token, "tag-open") && value === "<" && nextToken)
                inBlock = (blockTags.indexOf(nextToken.value) !== -1);

            // comments
            if (is(token, "comment.start"))
                inBlock = true;
            else if (is(token, "comment.end"))
                inBlock = false;

            // html indentation
            if (is(token, "tag-open") && value === "</") {
                // line break before closing tag unless we just had one
                if (is(token, "tag-open") && value === "</" && inBlock && !breakBefore)
                    rowsToAdd++;

                if (inCSS)
                    rowsToAdd = 1;

                indent--;
                inBlock = false;
            }

            // switch case
            onCaseLine = false;
            if (token.type === "keyword" && value.match(/^(case|default)$/)) {
                onCaseLine = true;
                inCase = true;
            } else if (token.type === "keyword" && value === "break")
                inCase = false;

            // add rows
            if (curRow !== row) {
                rowsToAdd = curRow;

                if (row)
                    rowsToAdd -= row;
            }

            if (rowsToAdd) {
                code = code.trimRight();
                for (; rowsToAdd > 0; rowsToAdd--)
                    code += "\n";

                breakBefore = true;

                // trim value if not in a comment or string
                if (!is(token, "comment") && !token.type.match(/^(comment|string)$/))
                    value = value.trimLeft();
            }

            if (value) {
                // whitespace
                if (token.type === "keyword" && value.match(/^(if|else|elseif|for|while|switch)$/)) {
                    spaceAfter = true;
                    trimNext();

                    // space before else, elseif
                    if (token.type === "keyword" && value.match(/^(else|elseif)$/)) {
                        if (code.match(/\}[\s]*$/)) {
                            code = code.trimRight();
                            breakBefore = false;
                            spaceBefore = true;
                        }
                    }
                // trim value after opening paren
                } else if (token.type === "paren.lparen") {
                    trimNext();

                    // whitespace after {
                    if (value.substr(-1) === "{")
                        spaceAfter = true;

                    // ensure curly brace is preceeded by whitespace
                    if (value.substr(0, 1) === "{") {
                        if (!code.match(/\s$/))
                            spaceBefore = true;

                        // collapse square and curly brackets together
                        if (code.trimRight().substr(-1) === '[') {
                            breakBefore = false;
                            spaceBefore = false;
                            if (code.match(/[\n][\s]*$/))
                                indent--;

                            code = code.trimRight();
                        }

                        if (inCSS) {
                            rowsToAdd++;
                            indent++;
                        }
                   }
                // remove space before closing paren
                } else if (token.type === "paren.rparen") {
                    code = code.replace(/ +$/, "");

                    // ensure curly brace is preceeded by whitespace
                    if (value.substr(0, 1) === "}") {
                        if (!code.match(/\s$/))
                            spaceBefore = true;

                        if (inCSS) {
                            rowsToAdd+=2;
                            indent--;
                        }
                    }

                    // collapse square and curly brackets together
                    if (value.substr(0, 1) === "]") {
                        if (code.trimRight().substr(-1) === '}') {
                            breakBefore = false;
                            spaceBefore = false;
                            if (code.match(/[\n][\s]*$/))
                                indent++;
                            code = code.trimRight();
                        }
                    }
                // add spaces around conditional operators
                } else if ((token.type === "keyword.operator" || token.type === "keyword") && value.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=)$/)) {
                    code = code.trimRight();
                    spaceBefore = true;
                    spaceAfter = true;
                    trimNext();
                // remove space before semicolon
                } else if (token.type === "punctuation.operator" && value === ';') {
                    code = code.trimRight();
                    spaceAfter = true;
                    trimNext();

                    if (inCSS)
                        rowsToAdd++;
                // space after colon
                } else if (token.type === "punctuation.operator" && value.match(/^(:|,)$/)) {
                    code = code.trimRight();
                    spaceAfter = true;
                    trimNext();
                // ensure space before php closing tag
                } else if (token.type === "support.php_tag" && value === "?>" && !breakBefore) {
                    code = code.trimRight();
                    spaceBefore = true;
                // ensure space before HTML attribute
                } else if (is(token, "attribute-name")) {
                    code = code.replace(/ +$/, "");
                    spaceBefore = true;
                // remove space around attribute equals
                } else if (is(token, "attribute-equals")) {
                    code = code.replace(/ +$/, "");
                    trimNext();
                // remove space before HTML closing tag
                } else if (is(token, "tag-close")) {
                    code = code.replace(/ +$/, "");
                    if(value === "/>")
                        spaceBefore = true;
                }

                // unindent if first paren is closing
                if (curRow !== row && rowTokens && !inCSS) {
                    abort = false;
                    for (i = 0; i<rowTokens.length && !abort; i++) {
                        if (rowTokens[i].type === "paren.rparen") {
                            indent--;
                            abort = true;
                        } else if (rowTokens[i].type === "paren.lparen")
                            abort = true;
                    }
                }

                // add indent to code
                if (breakBefore && !is(token, "comment")) {
                    var count = indent;
                    if (inCase && !onCaseLine)
                        count++;

                    if (indentNextLine) {
                        count++;
                        indentNextLine = false;
                    }

                    for (i = 0; i < count; i++)
                        code += tabString;
                }

                // indent if there are last paren is opening
                if (curRow !== row && rowTokens && !inCSS) {
                    indentNextLine = null;
                    abort = false;
                    for (i = rowTokens.length-1; i>=0 && !abort; i--) {
                        if (rowTokens[i].type === "paren.rparen") {
                            abort = true;
                        } else if (rowTokens[i].type === "paren.lparen") {
                            indent++;
                            indentNextLine = false;
                            abort = true;
                        }
                    }
                }

                // indent one line after if or else
                if (indentNextLine !== false && token.type === "keyword" && value.match(/^(if|else|elseif|for|while)$/))
                    indentNextLine = true;

                // add to code
                if (spaceBefore)
                    code += " ";

                code += value;

                if (spaceAfter)
                    code += " ";

                breakBefore = false;
                spaceBefore = false;
                spaceAfter = false;

                // line break after opening block tag or doctype
                if ((is(token, "tag-close") && (inBlock || blockTags.indexOf(tagName) !== -1)) || (is(token, "doctype") && value === ">")) {
                    // undo linebreak if tag is immediately closed
                    if (inBlock && nextToken && nextToken.value === "</")
                        rowsToAdd--;
                    else
                        rowsToAdd++;
                }

                // indent after opening tag
                if (is(token, "tag-open") && value === "<" && singletonTags.indexOf(nextToken.value) === -1)
                    indent++;

                // remove indent if unknown singleton
                if (is(token, "tag-name"))
                    tagName = value;

                if (is(token, "tag-close") && value === "/>" && singletonTags.indexOf(tagName) === -1)
                    indent--;

                row = curRow;
            }
        }

        token = nextToken;
    }

    code = code.trim();
    session.doc.setValue(code);
};

exports.commands = [{
    name: "beautify",
    exec: function(editor) {
        exports.beautify(editor.session);
    },
    bindKey: "Ctrl-Shift-B"
}];

});
<commit_msg>refactor and better curly handling<commit_after>/* ***** BEGIN LICENSE BLOCK *****
 * Distributed under the BSD license:
 *
 * Copyright (c) 2012, Ajax.org B.V.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Ajax.org B.V. nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ***** END LICENSE BLOCK ***** */

// [WIP]

define(function(require, exports, module) {
"use strict";
var TokenIterator = require("../token_iterator").TokenIterator;

function is(token, type) {
    return token.type.lastIndexOf(type + ".xml") > -1;
}

// do not indent after singleton tags or <html>
exports.singletonTags = ["area", "base", "br", "col", "command", "embed", "hr", "html", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];

// insert a line break after block level tags
exports.blockTags = ["article", "aside", "blockquote", "body", "div", "dl", "fieldset", "footer", "form", "head", "header", "html", "nav", "ol", "p", "script", "section", "style", "table", "tbody", "tfoot", "thead", "ul"];

exports.beautify = function(session) {
    var iterator = new TokenIterator(session, 0, 0);
    var token = iterator.getCurrentToken();
    var tabString = session.getTabString();
    var singletonTags = exports.singletonTags;
    var blockTags = exports.blockTags;
    var nextToken;
    var breakBefore = false;
    var spaceBefore = false;
    var spaceAfter = false;
    var code = "";
    var value = "";
    var tagName = "";
    var indent = 0;
    var onCaseLine = false;
    var row;
    var curRow = 0;
    var rowsToAdd = 0;
    var rowTokens = [];
    var abort = false;
    var i;
    var indentNextLine = false;
    var inTag = false;
    var inCSS = false;
    var inBlock = false;
    var inCase = false;

    var trimNext = function() {
        if (nextToken && nextToken.value)
            nextToken.value = nextToken.value.trim();
    };

    var trimLine = function() {
        code = code.replace(/ +$/, "");
    };

    while (token !== null) {
        curRow = iterator.getCurrentTokenRow();
        rowTokens = iterator.$rowTokens;
        nextToken = iterator.stepForward();

        if (typeof token !== "undefined") {
            value = token.value;

            // mode
            inCSS = (tagName === "style" || session.$modeId === "ace/mode/css");

            // in tag
            if (is(token, "tag-open"))
                inTag = true;

            if (is(token, "tag-close"))
                inTag = false;

            // are we in a block tag
            if (is(token, "tag-open") && value === "<" && nextToken)
                inBlock = (blockTags.indexOf(nextToken.value) !== -1);

            // comments
            if (is(token, "comment.start"))
                inBlock = true;
            else if (is(token, "comment.end"))
                inBlock = false;

            // html indentation
            if (is(token, "tag-open") && value === "</") {
                // line break before closing tag unless we just had one
                if (is(token, "tag-open") && value === "</" && inBlock && !breakBefore)
                    rowsToAdd++;

                if (inCSS)
                    rowsToAdd = 1;

                indent--;
                inBlock = false;
            }

            // line break before }
            if (!inTag && !rowsToAdd && token.type === "paren.rparen" && token.value.substr(0, 1) === "}") {
                rowsToAdd++;
            }

            // switch case
            onCaseLine = false;
            if (token.type === "keyword" && value.match(/^(case|default)$/)) {
                onCaseLine = true;
                inCase = true;
            } else if (token.type === "keyword" && value === "break")
                inCase = false;

            // add rows
            if (curRow != row) {
                rowsToAdd = curRow;

                if (row)
                    rowsToAdd -= row;
            }

            if (rowsToAdd) {
                code = code.trimRight();
                for (; rowsToAdd > 0; rowsToAdd--)
                    code += "\n";

                breakBefore = true;

                // trim value if not in a comment or string
                if (!is(token, "comment") && !token.type.match(/^(comment|string)$/))
                   value = value.trimLeft();
            }

            if (value) {
                // whitespace
                if (token.type === "keyword" && value.match(/^(if|else|elseif|for|while|switch)$/)) {
                    spaceAfter = true;
                    trimNext();

                    // space before else, elseif
                    if (token.type === "keyword" && value.match(/^(else|elseif)$/)) {
                        if (code.match(/\}[\s]*$/)) {
                            code = code.trimRight();
                            breakBefore = false;
                            spaceBefore = true;
                        }
                    }
                // trim value after opening paren
                } else if (token.type === "paren.lparen") {
                    trimNext();

                    // no one off indent after {
                    if (value.indexOf("{") > -1)
                        indentNextLine = false;

                    // whitespace after {
                    if (value.substr(-1) === "{")
                        spaceAfter = true;

                    // ensure curly brace is preceeded by whitespace
                    if (value.substr(0, 1) === "{") {
                        spaceBefore = true;

                        // collapse square and curly brackets together
                        if (code.substr(-1) !== '[' && code.trimRight().substr(-1) === '[') {
                            breakBefore = false;
                            spaceBefore = false;
                            indent--;
                            code = code.trimRight();
                        }
                    }
                // remove space before closing paren
                } else if (token.type === "paren.rparen") {
                    // ensure curly brace is preceeded by whitespace
                    if (value.substr(0, 1) === "}") {
                        spaceBefore = true;
                        if (inCSS) {
                            rowsToAdd+=2;
                        }
                    }

                    // collapse square and curly brackets together
                    if (value.substr(0, 1) === "]") {
                        if (code.substr(-1) !== '}' && code.trimRight().substr(-1) === '}') {
                            breakBefore = false;
                            spaceBefore = false;
                            indent++;
                            code = code.trimRight();
                        }
                    }

                    trimLine();
                // add spaces around conditional operators
                } else if ((token.type === "keyword.operator" || token.type === "keyword") && value.match(/^(=|==|===|!=|!==|&&|\|\||and|or|xor|\+=|.=|>|>=|<|<=)$/)) {
                    code = code.trimRight();
                    spaceBefore = true;
                    spaceAfter = true;
                    trimNext();
                // remove space before semicolon
                } else if (token.type === "punctuation.operator" && value === ';') {
                    code = code.trimRight();
                    spaceAfter = true;
                    trimNext();

                    if (inCSS)
                        rowsToAdd++;
                // space after colon or comma
                } else if (token.type === "punctuation.operator" && value.match(/^(:|,)$/)) {
                    code = code.trimRight();
                    spaceAfter = true;
                    trimNext();
                // ensure space before php closing tag
                } else if (token.type === "support.php_tag" && value === "?>" && !breakBefore) {
                    code = code.trimRight();
                    spaceBefore = true;
                // remove excess space before HTML attribute
                } else if (is(token, "attribute-name") && code.substr(-1).match(/^\s$/)) {
                    spaceBefore = true;
                // remove space around attribute equals
                } else if (is(token, "attribute-equals")) {
                    trimLine();
                    trimNext();
                // remove space before HTML closing tag
                } else if (is(token, "tag-close")) {
                    trimLine();
                    if(value === "/>")
                        spaceBefore = true;
                }

                // unindent
                if (token.type === "paren.rparen") {
                    indent--;
                }

                // add indent to code
                if (breakBefore && !is(token, "comment")) {
                    var count = indent;
                    if (inCase && !onCaseLine)
                        count++;

                    if (indentNextLine) {
                        count++;
                        indentNextLine = false;
                    }

                    for (i = 0; i < count; i++)
                        code += tabString;
                }

                // indent if there are last paren is opening
                if (token.type === "paren.lparen") {
                    indent++;
                }

                // indent one line after if or else
                if (token.type === "keyword" && value.match(/^(if|else|elseif|for|while)$/))
                    indentNextLine = true;

                // add to code
                if (spaceBefore && !breakBefore) {
                    trimLine();
                    code += " ";
                }

                code += value;

                if (spaceAfter)
                    code += " ";

                breakBefore = false;
                spaceBefore = false;
                spaceAfter = false;

                // line break after block tag or doctype
                if ((is(token, "tag-close") && (inBlock || blockTags.indexOf(tagName) !== -1)) || (is(token, "doctype") && value === ">")) {
                    // undo linebreak if tag is immediately closed
                    if (inBlock && nextToken && nextToken.value === "</")
                        rowsToAdd--;
                    else
                        rowsToAdd++;
                }

                // indent after opening tag
                if (is(token, "tag-open") && value === "<" && singletonTags.indexOf(nextToken.value) === -1)
                    indent++;

                // remove indent if unknown singleton
                if (is(token, "tag-name"))
                    tagName = value;

                if (is(token, "tag-close") && value === "/>" && singletonTags.indexOf(tagName) === -1)
                    indent--;

                // line break after {
                if (!inTag && token.type === "paren.lparen" && value.substr(-1) === "{") {
                    rowsToAdd++;
                }

                row = curRow;
            }
        }

        token = nextToken;
    }

    code = code.trim();
    session.doc.setValue(code);
};

exports.commands = [{
    name: "beautify",
    exec: function(editor) {
        exports.beautify(editor.session);
    },
    bindKey: "Ctrl-Shift-B"
}];

});
<|endoftext|>


<commit_before>(function () {
	function iterator(cols) {
		var p = { x: 0, y: 0 };
		function square() {
			p.x++;
			if (p.x >= cols) {
				p.x = 0;
				p.y++;
			}
		}
		function diag() {
			if (p.y === 0) {
				p.y = p.x + 1;
				p.x = 0;
			} else {
				p.x++;
				p.y--;
			}
		}
		return {
			ptr: function () { return { x: p.x, y: p.y }; },
			step: function () {
				square();

			}
		};
	}
	function placer() {
		var grid = [];
		return function (card, ptr) {
			var c = $(card),
				h = _.reduce(grid[ptr.x] || [], function (m, n) { return m + n; }, 0);
			c.css({ left: ptr.x * 200, top: h });
			if (!grid[ptr.x]) { grid[ptr.x] = []; }
			grid[ptr.x][ptr.y] = c.outerHeight();
		};
	}
	function group() {

		//find all cards
		var cards = $('div.card'),
			width = $(cards[0]).outerWidth(),
			columns = Math.floor($(window).width() / width);
		var sorted = _.sortBy(cards, function (c) { return -$(c).outerHeight(); });
		cards.addClass('absolute');
		var it = iterator(columns > 4 ? 4 : columns),
			place = placer();
		_.each(sorted, function (card) {
			var ptr = it.ptr();
			place(card, ptr);
			it.step();
		});
	}

	// On window load
	window.addEventListener('load', function load() {
		window.removeEventListener('load', load);
		group();
	});
	window.addEventListener('resize', function load() {
		group();
	});
})();
<commit_msg>movies<commit_after>(function () {
	function iterator(cols) {
		var p = { x: 0, y: 0 };
		function square() {
			p.x++;
			if (p.x >= cols) {
				p.x = 0;
				p.y++;
			}
		}
		function diag() {
			if (p.y === 0) {
				p.y = p.x + 1;
				p.x = 0;
			} else {
				p.x++;
				p.y--;
			}
		}
		return {
			ptr: function () { return { x: p.x, y: p.y }; },
			step: function () {
				square();

			}
		};
	}
	function placer() {
		var grid = [];
		return function (card, ptr) {
			var c = $(card),
				h = _.reduce(grid[ptr.x] || [], function (m, n) { return m + n; }, 0);
			c.css({ left: ptr.x * 200, top: h });
			if (!grid[ptr.x]) { grid[ptr.x] = []; }
			grid[ptr.x][ptr.y] = c.outerHeight();
		};
	}
	function group() {

		//find all cards
		var cards = $('div.card'),
			width = $(cards[0]).outerWidth(),
			columns = Math.floor($(window).width() / width);
		var sorted = _.sortBy(cards, function (c) { return -$(c).outerHeight(); });
		cards.addClass('absolute');
		var it = iterator(columns > 4 ? 4 : columns),
			place = placer();
		_.each(cards, function (card) {
			var ptr = it.ptr();
			place(card, ptr);
			it.step();
		});
	}

	// On window load
	window.addEventListener('load', function load() {
		window.removeEventListener('load', load);
		group();
	});
	window.addEventListener('resize', function load() {
		group();
	});
})();
<|endoftext|>


<commit_before>define(['util'], function (util) {
  function Life(options) {
    /* Encapsulate a single Life game */

    // Defaults
    var defaultOptions = {
      cellSize : 10,
      cellFill : '#87AFC7',
      cellBorder : '25383C',
      cellBorderSize : 1,
      controlSelector : 'Life-'
    };

    options = options || {};
    this.options = util.extend(defaultOptions, options);

    // Set controls and event listeners
    this._initControls();

    // Save the size of the grid
    this.gridSize = {
      x : Math.floor(this.canvasControl.width / this.options.cellSize),
      y : Math.floor(this.canvasControl.height / this.options.cellSize)
    };

    // Build game grid
    this.gameGrid = this._makeGrid();

  }

  Life.prototype._initControls = function() {
    /* Initialize handlers and etc. */
    var controls = [
      { id : 'start', handler : this.start, event : 'click' },
      { id : 'stop', handler : this.stop, event : 'click' },
      { id : 'clear', handler : this.clear, event : 'click' },
      { id : 'speed', handler : this.updateFps, event : 'change' },
      { id : 'canvas', handler : this.click, event : 'mousedown' }
    ];

    util.registerControls(this, controls, this.options.controlSelector);
    this.ctx = this.canvasControl.getContext('2d');

  };

  Life.prototype.pixelsToCoords = function(x, y) {
    return {
      x : Math.floor(x / this.options.cellSize),
      y : Math.floor(y / this.options.cellSize)
    };
  };

  Life.prototype.coordsToPixels = function(x, y) {
    /* Get actual canvas coords for a life grid point */
    return {
      x : this.options.cellSize * x,
      y : this.options.cellSize * y
    };
  }

  Life.prototype.click = function(e) {
    var x = e.x - this.canvasControl.offsetLeft;
    var y = e.y - this.canvasControl.offsetTop;

    // Account for the border
    var re = /px$/;
    var canvasStyle = getComputedStyle(this.canvasControl);
    x -= canvasStyle.getPropertyValue('border-left-width').replace(re, '');
    y -= canvasStyle.getPropertyValue('border-top-width').replace(re, '');

    // Invalid click
    if(x < 0 || y < 0) return;

    var coords = this.pixelsToCoords(x, y);
    var cell = this.gameGrid[coords.x][coords.y];

    // Flip the alive state
    cell.alive = !cell.alive;

    // Draw or clear as appropriate
    cell.alive ? this.drawCell(coords.x, coords.y) : this.clearCell(coords.x, coords.y);

  };

  Life.prototype._makeGrid = function() {
    /* Generate a new grid of size (x, y) */

    var gameGrid = [];
    for(var i = 0; i < this.gridSize.x; ++i) {
      gameGrid[i] = [];
      for(var j = 0; j < this.gridSize.y; ++j) {
        gameGrid[i][j] = { neighbours : 0, alive : false };
      }
    }
    return gameGrid;
  };

  Life.prototype.clear = function() {
    /* Clear the board */
    for(var i = 0; i < this.gameGrid.length; ++i) {
      for(var j = 0; j < this.gameGrid[i].length; ++j) {
        this.gameGrid[i][j].alive = false;
        this.gameGrid[i][j].neighbours = 0;
      }
    }
    this.ctx.clearRect(0, 0, this.canvasControl.width, this.canvasControl.height);
  };

  Life.prototype.stop = function() {
    /* Stop the game. */
    if(this.started) {
      this._stopTimer();
      this.started = false;
    }
  };

  Life.prototype.start = function() {
    /* Start the game. */

    // If not started, update the FPS, which starts the game
    if(!this.started) {
      this._startTimer();
      this.started = true;
    }
  };

  Life.prototype._stopTimer = function() {
    window.clearInterval(this.interval);
    delete this.interval;
  };

  Life.prototype._startTimer = function() {
    var fps = this.speedControl.value;
    // Milliseconds in between ticks
    var ms = Math.floor(1000 / fps);
    this.interval = window.setInterval(this._tick.bind(this), ms);
  };

  Life.prototype.updateFps = function() {
    if(!this.started) return;
    this._stopTimer();
    this._startTimer();
  };

  Life.prototype._tick = function() {
    // Count the neighbours of each
    for(var x = 0; x < this.gridSize.x; ++x) {
      for(var y = 0; y < this.gridSize.y; ++y) {
        this._countNeighbours(x, y);
      }
    }

    // Check each to see if alive and reset the neighbours count
    for(var x = 0; x < this.gridSize.x; ++x) {
      for(var y = 0; y < this.gridSize.y; ++y) {
        cell = this.gameGrid[x][y];

        if(cell.alive) {
          // Live if neighbours are 2 or 3, die otherwise
          cell.alive = (cell.neighbours === 2 || cell.neighbours === 3);
        } else {
          // Become alive if exactly 3 neighbours
          cell.alive = (cell.neighbours === 3);
        }

        cell.neighbours = 0;

        // Draw or clear the cell
        cell.alive ? this.drawCell(x, y) : this.clearCell(x, y);
      }
    }
  }

  Life.prototype.drawCell = function(x, y) {
    /* Draw the cell at position (x, y) */
    var coords = this.coordsToPixels(x, y);
    var cellSize = this.options.cellSize;

    util.drawSquare(this.ctx, coords, cellSize, this.options.cellBorder);

    // Border size
    var bs = this.options.cellBorderSize;
    // Move up+left by border size
    coords.x += bs;
    coords.y += bs;

    // Reduce size by twice border size so border appears on all sides
    cellSize -= 2 * bs;
    util.drawSquare(this.ctx, coords, cellSize, this.options.cellFill);
  };

  Life.prototype.clearCell = function(x, y) {
    /* Undraw cell at position (x, y) */
    var coords = this.coordsToPixels(x, y);
    util.clearSquare(this.ctx, coords, this.options.cellSize);
  };

  Life.prototype._getNeighbours = function(x, y) {
    /* Return array of neighbouring cells to cell at (x, y) */

    var width = this.gridSize.x;
    var height = this.gridSize.y;

    var neighbours = [];

    // i, j are offsets from x, y.  Make sure to not go out of bounds
    for(var i = (x && -1); i <= ((width-x-1) && 1); ++i) {
      for(var j = (y && -1); j <= ((height-y-1) && 1); ++j) {
        // A cell is not its own neighbour
        if(i || j) neighbours.push(this.gameGrid[x + i][y + j]);
      }
    }

    return neighbours;
  };

  Life.prototype._countNeighbours = function(x, y) {
    /*
     * Add 1 to the number of neighbours of each neighbour
     * of cell (x, y) if cell (x, y) is alive.
     */

    // Add to neighbours only if alive
    if(!this.gameGrid[x][y].alive) return;

    // Don't go out of bounds
    var neighbours = this._getNeighbours(x, y);
    for(var i = 0; i < neighbours.length; ++i) {
      neighbours[i].neighbours += 1;
    }
  };

  return Life;

});
<commit_msg>Fixup for clicking when scrolling etc<commit_after>define(['sg', 'util'], function (sg, util) {
  function Life(options) {
    /* Encapsulate a single Life game */

    // Defaults
    var defaultOptions = {
      cellSize : 10,
      cellFill : '#87AFC7',
      cellBorder : '25383C',
      cellBorderSize : 1,
      controlSelector : 'Life-'
    };

    options = options || {};
    this.options = util.extend(defaultOptions, options);

    // Set controls and event listeners
    this._initControls();

    // Save the size of the grid
    this.gridSize = {
      x : Math.floor(this.canvasControl.width / this.options.cellSize),
      y : Math.floor(this.canvasControl.height / this.options.cellSize)
    };

    // Build game grid
    this.gameGrid = this._makeGrid();

  }

  Life.prototype._initControls = function() {
    /* Initialize handlers and etc. */
    var controls = [
      { id : 'start', handler : this.start, event : 'click' },
      { id : 'stop', handler : this.stop, event : 'click' },
      { id : 'clear', handler : this.clear, event : 'click' },
      { id : 'speed', handler : this.updateFps, event : 'change' },
      { id : 'canvas', handler : this.click, event : 'mousedown' }
    ];

    sg.registerControls(this, controls, this.options.controlSelector);
    this.ctx = this.canvasControl.getContext('2d');

  };

  Life.prototype.pixelsToCoords = function(x, y) {
    return {
      x : Math.floor(x / this.options.cellSize),
      y : Math.floor(y / this.options.cellSize)
    };
  };

  Life.prototype.coordsToPixels = function(x, y) {
    /* Get actual canvas coords for a life grid point */
    return {
      x : this.options.cellSize * x,
      y : this.options.cellSize * y
    };
  }

  Life.prototype.click = function(e) {
    // Compute the click relative to the canvas
    var offset = {
      x: 0,
      y: 0
    };
    // Current element
    var el = this.canvasControl;
    // Loop through all parents to get total offset
    do {
      offset.x += el.offsetLeft - el.scrollLeft;
      offset.y += el.offsetTop - el.scrollTop;
    } while(el = el.offsetParent)
    var x = e.clientX - offset.x;
    var y = e.clientY - offset.y;

    // Account for the border
    var re = /px$/;
    var canvasStyle = getComputedStyle(this.canvasControl);
    x -= canvasStyle.getPropertyValue('border-left-width').replace(re, '');
    y -= canvasStyle.getPropertyValue('border-top-width').replace(re, '');

    var coords = this.pixelsToCoords(x, y);

    // Invalid click detection
    if(coords.x < 0 || coords.y < 0 ||
       coords.x >= this.gridSize.x || coords.y >= this.gridSize.y) return;

    var cell = this.gameGrid[coords.x][coords.y];

    // Flip the alive state
    cell.alive = !cell.alive;

    // Draw or clear as appropriate
    cell.alive ? this.drawCell(coords.x, coords.y) : this.clearCell(coords.x, coords.y);

  };

  Life.prototype._makeGrid = function() {
    /* Generate a new grid of size (x, y) */

    var gameGrid = [];
    for(var i = 0; i < this.gridSize.x; ++i) {
      gameGrid[i] = [];
      for(var j = 0; j < this.gridSize.y; ++j) {
        gameGrid[i][j] = { neighbours : 0, alive : false };
      }
    }
    return gameGrid;
  };

  Life.prototype.clear = function() {
    /* Clear the board */
    for(var i = 0; i < this.gameGrid.length; ++i) {
      for(var j = 0; j < this.gameGrid[i].length; ++j) {
        this.gameGrid[i][j].alive = false;
        this.gameGrid[i][j].neighbours = 0;
      }
    }
    this.ctx.clearRect(0, 0, this.canvasControl.width, this.canvasControl.height);
  };

  Life.prototype.stop = function() {
    /* Stop the game. */
    if(this.started) {
      this._stopTimer();
      this.started = false;
    }
  };

  Life.prototype.start = function() {
    /* Start the game. */

    // If not started, update the FPS, which starts the game
    if(!this.started) {
      this._startTimer();
      this.started = true;
    }
  };

  Life.prototype._stopTimer = function() {
    window.clearInterval(this.interval);
    delete this.interval;
  };

  Life.prototype._startTimer = function() {
    var fps = this.speedControl.value;
    // Milliseconds in between ticks
    var ms = Math.floor(1000 / fps);
    this.interval = window.setInterval(this._tick.bind(this), ms);
  };

  Life.prototype.updateFps = function() {
    if(!this.started) return;
    this._stopTimer();
    this._startTimer();
  };

  Life.prototype._tick = function() {
    // Count the neighbours of each
    for(var x = 0; x < this.gridSize.x; ++x) {
      for(var y = 0; y < this.gridSize.y; ++y) {
        this._countNeighbours(x, y);
      }
    }

    // Check each to see if alive and reset the neighbours count
    for(var x = 0; x < this.gridSize.x; ++x) {
      for(var y = 0; y < this.gridSize.y; ++y) {
        cell = this.gameGrid[x][y];

        if(cell.alive) {
          // Live if neighbours are 2 or 3, die otherwise
          cell.alive = (cell.neighbours === 2 || cell.neighbours === 3);
        } else {
          // Become alive if exactly 3 neighbours
          cell.alive = (cell.neighbours === 3);
        }

        cell.neighbours = 0;

        // Draw or clear the cell
        cell.alive ? this.drawCell(x, y) : this.clearCell(x, y);
      }
    }
  }

  Life.prototype.drawCell = function(x, y) {
    /* Draw the cell at position (x, y) */
    var coords = this.coordsToPixels(x, y);
    var cellSize = this.options.cellSize;

    util.drawSquare(this.ctx, coords, cellSize, this.options.cellBorder);

    // Border size
    var bs = this.options.cellBorderSize;
    // Move up+left by border size
    coords.x += bs;
    coords.y += bs;

    // Reduce size by twice border size so border appears on all sides
    cellSize -= 2 * bs;
    util.drawSquare(this.ctx, coords, cellSize, this.options.cellFill);
  };

  Life.prototype.clearCell = function(x, y) {
    /* Undraw cell at position (x, y) */
    var coords = this.coordsToPixels(x, y);
    util.clearSquare(this.ctx, coords, this.options.cellSize);
  };

  Life.prototype._getNeighbours = function(x, y) {
    /* Return array of neighbouring cells to cell at (x, y) */

    var width = this.gridSize.x;
    var height = this.gridSize.y;

    var neighbours = [];

    // i, j are offsets from x, y.  Make sure to not go out of bounds
    for(var i = (x && -1); i <= ((width-x-1) && 1); ++i) {
      for(var j = (y && -1); j <= ((height-y-1) && 1); ++j) {
        // A cell is not its own neighbour
        if(i || j) neighbours.push(this.gameGrid[x + i][y + j]);
      }
    }

    return neighbours;
  };

  Life.prototype._countNeighbours = function(x, y) {
    /*
     * Add 1 to the number of neighbours of each neighbour
     * of cell (x, y) if cell (x, y) is alive.
     */

    // Add to neighbours only if alive
    if(!this.gameGrid[x][y].alive) return;

    // Don't go out of bounds
    var neighbours = this._getNeighbours(x, y);
    for(var i = 0; i < neighbours.length; ++i) {
      neighbours[i].neighbours += 1;
    }
  };

  return Life;

});
<|endoftext|>