<commit_before>$(function() {
  $('.component-demos .icon-all').on('click', function() {
    if ($(this).hasClass('expand')) {
      $(this).removeClass('expand');
      $('.code-box .highlight').animate({
        height: 'hide',
        opacity: 0
      }, 150);
    } else {
      $(this).addClass('expand');
      $('.code-box .highlight').animate({
        height: 'show',
        opacity: 1
      }, 150);
    }
  });

  $('.code-box').each(function(i, item) {
    item = $(item);
    item.find('.highlight').appendTo(item);
  });

  $('.code-boxes').on('click', '.collapse', function() {
    $(this).parent().parent().find('.highlight').animate({
      height: 'toggle',
      opacity: 'toggle'
    }, 150);
  });

  var navFunc = {
    navStrArr: [],
    init: function() {
      var self = this;
      self.navBox = $(".nav");
      self.navBar = self.navBox.find(".bar");
      self.navList = self.navBox.find("ul li");
      self.navNum = $(".current").index();
      self.search($(".search"));
      self.navBarAnim();
      self.navResize(null);
      $(window).bind("resize", self.navResize);
    },
    navResize: function(e) {
      var self = navFunc;
      self.navBar.css("left", self.navList.width() * self.navNum);

      self.navList.eq(self.navNum).find("a").addClass("hover");
    },
    search: function(c) {
      var self = this;
      self.searchBox = c;
      self.searchInput = self.searchBox.find("input[type='text']");
      self.searchBtn = self.searchBox.find("button");
      self.searchInput.focus(function(e) {
        $(this).addClass("focus");
        self.searchBtn.css("left", self.searchBox.width() + 13);
      });
      self.searchInput.blur(function(e) {
        if (!self.searchInput.val()) {
          self.searchBtn.attr("style", "");
          $(this).removeClass("focus");
        }
      });
      self.searchBtn.click(function(e) {
        self.searchBox.find("form").submit();
      });
    },
    navBarAnim: function() {
      var self = this,
        delay;

      function startBarAnim(num) {
        self.navBar.css("left", self.navList.width() * num);
        self.navList.eq(num).find("a").addClass("hover");
      }
      self.navList.bind("mouseenter", function(e) {
        clearTimeout(delay);
        var m = e.currentTarget;
        self.navList.find("a").removeClass("hover");
        self.navBar.addClass("barAnim").css("left", $(m).width() * $(m).index());
      });
      self.navList.bind("mouseleave", function(e) {
        delay = setTimeout(function() {
          startBarAnim(self.navNum);
        }, 500);
      });
    }
  };
  navFunc.init();
  var listFunc = {
    num: 0,
    cnum: 0,
    init: function() {
      var self = this;
      self.listBox = $(".aside-container>ul");
      if (!self.listBox.length) {
        return;
      }
      self.getUrlNum();
      self.listBox.children().eq(self.num).attr("open", true).find("ul").css("display", "block");
      //添加标题事件；
      self.addTitleEvent();
    },
    getUrlNum: function() {
      var self = this,
        url = location.href,
        str = "";
      //console.log(self.listBox.find("a"))
      for (var i = 0; i < self.listBox.find("a").length; i++) {
        var m = self.listBox.find("a").eq(i);
        if (m.attr("href") == "./" || url.indexOf(m.attr("href")) >= 0) {
          self.num = m.parent().parent().parent().index();
          self.cnum = m.parent().index();
        }
      }
    },
    addTitleEvent: function() {
      var self = this;
      var title = self.listBox.find("h4");
      title.bind("click", function(e) {
        var parent = $(this).parent();
        if (parent.attr("open")) {
          parent.removeAttr("open");
          if (parent.index() == self.num) {
            $(this).addClass("current");
          }
        } else {
          parent.attr("open", true);
          if (parent.index() == self.num) {
            $(this).removeClass("current");
          }
        }
        parent.find("ul").slideToggle(300);
      });
    }
  };
  listFunc.init();
});
<commit_msg>slideToggle<commit_after>$(function() {
  $('.component-demos .icon-all').on('click', function() {
    //if ($(this).hasClass('expand')) {
    //  $(this).removeClass('expand');
    //  $('.code-box .highlight').animate({
    //    height: 'hide',
    //    opacity: 0
    //  }, 150);
    //} else {
    //  $(this).addClass('expand');
    //  $('.code-box .highlight').animate({
    //    height: 'show',
    //    opacity: 1
    //  }, 150);
    //}
      $('.code-box .highlight').slideToggle(150);
  });

  $('.code-box').each(function(i, item) {
    item = $(item);
    item.find('.highlight').appendTo(item);
  });

  $('.code-boxes').on('click', '.collapse', function() {
    //$(this).parent().parent().find('.highlight').animate({
    //  height: 'toggle',
    //  opacity: 'toggle'
    //}, 150);
      $(this).parent().parent().find('.highlight').slideToggle(150);
  });

  var navFunc = {
    navStrArr: [],
    init: function() {
      var self = this;
      self.navBox = $(".nav");
      self.navBar = self.navBox.find(".bar");
      self.navList = self.navBox.find("ul li");
      self.navNum = $(".current").index();
      self.search($(".search"));
      self.navBarAnim();
      self.navResize(null);
      $(window).bind("resize", self.navResize);
    },
    navResize: function(e) {
      var self = navFunc;
      self.navBar.css("left", self.navList.width() * self.navNum);

      self.navList.eq(self.navNum).find("a").addClass("hover");
    },
    search: function(c) {
      var self = this;
      self.searchBox = c;
      self.searchInput = self.searchBox.find("input[type='text']");
      self.searchBtn = self.searchBox.find("button");
      self.searchInput.focus(function(e) {
        $(this).addClass("focus");
        self.searchBtn.css("left", self.searchBox.width() + 13);
      });
      self.searchInput.blur(function(e) {
        if (!self.searchInput.val()) {
          self.searchBtn.attr("style", "");
          $(this).removeClass("focus");
        }
      });
      self.searchBtn.click(function(e) {
        self.searchBox.find("form").submit();
      });
    },
    navBarAnim: function() {
      var self = this,
        delay;

      function startBarAnim(num) {
        self.navBar.css("left", self.navList.width() * num);
        self.navList.eq(num).find("a").addClass("hover");
      }
      self.navList.bind("mouseenter", function(e) {
        clearTimeout(delay);
        var m = e.currentTarget;
        self.navList.find("a").removeClass("hover");
        self.navBar.addClass("barAnim").css("left", $(m).width() * $(m).index());
      });
      self.navList.bind("mouseleave", function(e) {
        delay = setTimeout(function() {
          startBarAnim(self.navNum);
        }, 500);
      });
    }
  };
  navFunc.init();
  var listFunc = {
    num: 0,
    cnum: 0,
    init: function() {
      var self = this;
      self.listBox = $(".aside-container>ul");
      if (!self.listBox.length) {
        return;
      }
      self.getUrlNum();
      self.listBox.children().eq(self.num).attr("open", true).find("ul").css("display", "block");
      //添加标题事件；
      self.addTitleEvent();
    },
    getUrlNum: function() {
      var self = this,
        url = location.href,
        str = "";
      //console.log(self.listBox.find("a"))
      for (var i = 0; i < self.listBox.find("a").length; i++) {
        var m = self.listBox.find("a").eq(i);
        if (m.attr("href") == "./" || url.indexOf(m.attr("href")) >= 0) {
          self.num = m.parent().parent().parent().index();
          self.cnum = m.parent().index();
        }
      }
    },
    addTitleEvent: function() {
      var self = this;
      var title = self.listBox.find("h4");
      title.bind("click", function(e) {
        var parent = $(this).parent();
        if (parent.attr("open")) {
          parent.removeAttr("open");
          if (parent.index() == self.num) {
            $(this).addClass("current");
          }
        } else {
          parent.attr("open", true);
          if (parent.index() == self.num) {
            $(this).removeClass("current");
          }
        }
        parent.find("ul").slideToggle(300);
      });
    }
  };
  listFunc.init();
});
<|endoftext|>


<commit_before>export default class BasicNode {
  constructor(id, graph) {
    this.id = id;
    this.graph = graph;
  }

  children(oneLevel = true) {
    return this.graph.children(this.id, oneLevel)
  }

  directParents() {
    return this.graph.directParents(this.id)
  }

  get maxDistanceFromRoot() {
    if (_.isUndefined(this._maxDistanceFromRoot)) {
      this._maxDistanceFromRoot = this._calculateMaxDistanceFromRoot([this])
    }
    return this._maxDistanceFromRoot
  }

  _calculateMaxDistanceFromRoot(nodesToIgnore): integer {
    if (_.isUndefined(this._maxDistanceFromRoot)) {
      const ancestors = _.uniq(_.flatten(this.directParents())).filter(node => (!_.some(nodesToIgnore, s => s.id === node.id)))
      const distances = ancestors.map(n => n._calculateMaxDistanceFromRoot(nodesToIgnore.concat([this])))

      this._maxDistanceFromRoot = distances.length > 0 ? Math.max(...distances) + 1 : 0
    }
    return this._maxDistanceFromRoot
  }
}
<commit_msg>Set distance to root to infinity in graph work.<commit_after>export default class BasicNode {
  constructor(id, graph) {
    this.id = id;
    this.graph = graph;
  }

  children(oneLevel = true) {
    return this.graph.children(this.id, oneLevel)
  }

  directParents() {
    return this.graph.directParents(this.id)
  }

  get maxDistanceFromRoot() {
    if (_.isUndefined(this._maxDistanceFromRoot)) {
      this._maxDistanceFromRoot = this._calculateMaxDistanceFromRoot([this])
    }
    return this._maxDistanceFromRoot
  }

  _calculateMaxDistanceFromRoot(nodesToIgnore): integer {
    if (_.isUndefined(this._maxDistanceFromRoot)) {
      const parents = _.uniq(_.flatten(this.directParents()))
      if (_.some(parents, node => !_.some(nodesToIgnore, s => s.id === node.id))){
        return -Infinity
      }
      const distances = parents.map(n => n._calculateMaxDistanceFromRoot(nodesToIgnore.concat([this])))

      this._maxDistanceFromRoot = distances.length > 0 ? Math.max(...distances) + 1 : 0
    }
    return this._maxDistanceFromRoot
  }
}
<|endoftext|>


<commit_before>

'use strict';

var _ = require('lodash');

var value = function(v) {
  return (v === undefined || v === null) ? '' : v;
  return v;
};

//
module.exports.index = function(config, objects) {
  var html = module.exports.breadcrumb(config, [
    [ '/' + config.plural, config.Plural]
  ]);
  html += '
' + _.capitalize(config.Plural) + '
';
  html += module.exports.table(config.fields, objects, config.adminpath + '/' + config.plural);
  return html;
};

//
module.exports.show = function(config, object) {
  var title = _.capitalize(config.Name) + ' #' + object.id;

  var html = module.exports.breadcrumb(config, [
    [ '/' + config.plural, config.Plural],
    [ '/' + config.plural + '/' + object.id, title]
  ]);

  html += '
' + title + '
';
  html += '
';
  html += '
';
  config.fields.forEach(function(field) {
    html += '
' + field + '	' + object[field] + '
';
  });
  html += '

';

  return html;
};

//
module.exports.breadcrumb = function(config, lis) {
  var html = '
';
  html += '
Admin
';
  lis.forEach(function(li) {
    html += '
';
    html += '';
    html += li[1];
    html += '
';
  });
  html += '
';
  return html;
};

//
module.exports.table = function(fields, objects, path) {

  fields = _.reject(fields, function(el) { return el === 'id'; });

  var html = '
';
  html += '
';
  // thead
  html += '

';
  html += 'id	';
  fields.forEach(function(field) {
    html += '' + field + '';
  });
  html += 'Actions	';
  html += '

';

  // tbody
  objects.forEach(function(obj) {
    var objpath = [ path, obj.id ].join('/');
    html += '
';
    html += '#' + obj.id + '	'
    fields.forEach(function(field) {
      html += '' + value(obj[field]) + '';
    });
    html += 'Voir	'
    html += '
';
  });
  html += '

';

  return html;
};
<commit_msg>Admin show : fix values displayed<commit_after>

'use strict';

var _ = require('lodash');

var value = function(v) {
  return (v === undefined || v === null) ? '' : v;
  return v;
};

//
module.exports.index = function(config, objects) {
  var html = module.exports.breadcrumb(config, [
    [ '/' + config.plural, config.Plural]
  ]);
  html += '
' + _.capitalize(config.Plural) + '
';
  html += module.exports.table(config.fields, objects, config.adminpath + '/' + config.plural);
  return html;
};

//
module.exports.show = function(config, object) {
  var title = _.capitalize(config.Name) + ' #' + object.id;

  var html = module.exports.breadcrumb(config, [
    [ '/' + config.plural, config.Plural],
    [ '/' + config.plural + '/' + object.id, title]
  ]);

  html += '
' + title + '
';
  html += '
';
  html += '
';
  config.fields.forEach(function(field) {
    html += '
' + field + '	' + value(object[field]) + '
';
  });
  html += '

';

  return html;
};

//
module.exports.breadcrumb = function(config, lis) {
  var html = '
';
  html += '
Admin
';
  lis.forEach(function(li) {
    html += '
';
    html += '';
    html += li[1];
    html += '
';
  });
  html += '
';
  return html;
};

//
module.exports.table = function(fields, objects, path) {

  fields = _.reject(fields, function(el) { return el === 'id'; });

  var html = '
';
  html += '
';
  // thead
  html += '

';
  html += 'id	';
  fields.forEach(function(field) {
    html += '' + field + '';
  });
  html += 'Actions	';
  html += '

';

  // tbody
  objects.forEach(function(obj) {
    var objpath = [ path, obj.id ].join('/');
    html += '
';
    html += '#' + obj.id + '	'
    fields.forEach(function(field) {
      html += '' + value(obj[field]) + '';
    });
    html += 'Voir	'
    html += '
';
  });
  html += '

';

  return html;
};
<|endoftext|>


<commit_before>export class Animations {
	constructor(game) {
		this.game = game;
		this.movementPoints = 0;
	}

	walk(creature, path, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			path = path.slice(0, opts.customMovementPoint);
			// For compatibility
			this.movementPoints = creature.remainingMove;
			creature.remainingMove = opts.customMovementPoint;
		}

		game.freezedInput = true;

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		let hexId = 0;

		creature.healthHide();

		let anim = function() {
			let hex = path[hexId];

			if (hexId < path.length && (creature.remainingMove > 0 || opts.ignoreMovementPoint)) {
				this.leaveHex(creature, hex, opts);
			} else {
				this.movementComplete(creature, path[path.length - 1], anim_id, opts);
				return;
			}

			let nextPos = game.grid.hexes[hex.y][hex.x - creature.size + 1];
			let speed = !opts.overrideSpeed ? creature.animation.walk_speed : opts.overrideSpeed;

			let tween = game.Phaser.add.tween(creature.grp)
				.to(nextPos.displayPos, parseInt(speed), Phaser.Easing.Linear.None)
				.start();

			// Ignore traps for hover creatures, unless this is the last hex
			let enterHexOpts = $j.extend({
				ignoreTraps: creature.movementType() !== "normal" && hexId < path.length - 1
			}, opts);

			tween.onComplete.add(() => {
				if (creature.dead) {
					// Stop moving if creature has died while moving
					this.movementComplete(creature, hex, anim_id, opts);
					return;
				}

				// Sound Effect
				game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

				if (!opts.ignoreMovementPoint) {
					creature.remainingMove--;

					if (opts.customMovementPoint === 0) {
						creature.travelDist++;
					}
				}

				this.enterHex(creature, hex, enterHexOpts);

				anim(); // Next tween
			});

			hexId++;
		}.bind(this);

		anim();
	}

	fly(creature, path, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			path = path.slice(0, opts.customMovementPoint);
			// For compatibility
			this.movementPoints = creature.remainingMove;
			creature.remainingMove = opts.customMovementPoint;
		}

		game.freezedInput = true;

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		let hexId = 0;

		creature.healthHide();

		let hex = path[0];

		let start = game.grid.hexes[creature.y][creature.x - creature.size + 1];
		let currentHex = game.grid.hexes[hex.y][hex.x - creature.size + 1];

		this.leaveHex(creature, start, opts);

		let speed = !opts.overrideSpeed ? creature.animation.walk_speed : opts.overrideSpeed;

		let tween = game.Phaser.add.tween(creature.grp)
			.to(currentHex.displayPos, parseInt(speed), Phaser.Easing.Linear.None)
			.start();

		tween.onComplete.add(() => {
			// Sound Effect
			game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

			if (!opts.ignoreMovementPoint) {
				// Determine distance
				let distance = 0;
				let k = 0;
				while (!distance && start != currentHex) {
					k++;

					if (arrayUtils.findPos(start.adjacentHex(k), currentHex)) {
						distance = k;
					}
				}

				creature.remainingMove -= distance;
				if (opts.customMovementPoint === 0) {
					creature.travelDist += distance;
				}
			}

			this.enterHex(creature, hex, opts);
			this.movementComplete(creature, hex, anim_id, opts);
			return;
		});
	}

	teleport(creature, path, opts) {
		let game = this.game,
			hex = path[0],
			currentHex = game.grid.hexes[hex.y][hex.x - creature.size + 1];

		this.leaveHex(creature, currentHex, opts);

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		// FadeOut
		let tween = game.Phaser.add.tween(creature.grp)
			.to({
				alpha: 0
			}, 500, Phaser.Easing.Linear.None)
			.start();

		tween.onComplete.add(() => {
			// Sound Effect
			game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

			// position
			creature.grp.x = currentHex.displayPos.x;
			creature.grp.y = currentHex.displayPos.y;

			// FadeIn
			let tween = game.Phaser.add.tween(creature.grp)
				.to({
					alpha: 1
				}, 500, Phaser.Easing.Linear.None)
				.start();

			this.enterHex(creature, hex, opts);
			this.movementComplete(creature, hex, anim_id, opts);
			return;
		});
	}

	push(creature, path, opts) {
		opts.pushed = true;
		this.walk(creature, path, opts);
	}

	//--------Special Functions---------//

	enterHex(creature, hex, opts) {
		let game = this.game;

		creature.cleanHex();
		creature.x = hex.x - 0;
		creature.y = hex.y - 0;
		creature.pos = hex.pos;
		creature.updateHex();

		game.onStepIn(creature, hex, opts);

		creature.pickupDrop();

		opts.callbackStepIn(hex);

		game.grid.orderCreatureZ();
	}

	leaveHex(creature, hex, opts) {
		let game = this.game;

		if (!opts.pushed) {
			creature.faceHex(hex, creature.hexagons[0]); // Determine facing
		}

		game.onStepOut(creature, creature.hexagons[0]); // Trigger
		game.grid.orderCreatureZ();
	}

	movementComplete(creature, hex, anim_id, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			creature.remainingMove = this.movementPoints;
		}

		game.grid.updateDisplay();
		// TODO: Turn around animation
		if (opts.turnAroundOnComplete) {
			creature.facePlayerDefault();
		}

		// TODO: Reveal health indicator
		creature.healthShow();

		game.onCreatureMove(creature, hex); // Trigger

		creature.hexagons.forEach((hex) => {
			hex.pickupDrop(creature);
		});

		game.grid.orderCreatureZ();

		let queue = game.animationQueue.filter((item) => item != anim_id);

		if (queue.length === 0) {
			game.freezedInput = false;
		}

		game.animationQueue = queue;
	}

	projectile(this_2, target, sprite_id, path, args, start_x, start_y) {
		let game = this.game,
			dist = arrayUtils.filterCreature(path.slice(0), false, false).length,
			emissionPoint = {
				x: this_2.creature.grp.x + start_x,
				y: this_2.creature.grp.y + start_y
			},
			targetPoint = {
				x: target.grp.x + 52,
				y: target.grp.y - 20
			},
			// Sprite id here
			sprite = game.grid.creatureGroup.create(emissionPoint.x, emissionPoint.y, sprite_id),
			duration = dist * 75;

		sprite.anchor.setTo(0.5);
		sprite.rotation = -Math.PI / 3 + args.direction * Math.PI / 3;
		let tween = game.Phaser.add.tween(sprite)
			.to({
				x: targetPoint.x,
				y: targetPoint.y
			}, duration, Phaser.Easing.Linear.None)
			.start();

		return [tween, sprite, dist];
	}
}
<commit_msg>Added imports to animation<commit_after>import * as arrayUtils from "./utility/arrayUtils";

export class Animations {
	constructor(game) {
		this.game = game;
		this.movementPoints = 0;
	}

	walk(creature, path, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			path = path.slice(0, opts.customMovementPoint);
			// For compatibility
			this.movementPoints = creature.remainingMove;
			creature.remainingMove = opts.customMovementPoint;
		}

		game.freezedInput = true;

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		let hexId = 0;

		creature.healthHide();

		let anim = function() {
			let hex = path[hexId];

			if (hexId < path.length && (creature.remainingMove > 0 || opts.ignoreMovementPoint)) {
				this.leaveHex(creature, hex, opts);
			} else {
				this.movementComplete(creature, path[path.length - 1], anim_id, opts);
				return;
			}

			let nextPos = game.grid.hexes[hex.y][hex.x - creature.size + 1];
			let speed = !opts.overrideSpeed ? creature.animation.walk_speed : opts.overrideSpeed;

			let tween = game.Phaser.add.tween(creature.grp)
				.to(nextPos.displayPos, parseInt(speed), Phaser.Easing.Linear.None)
				.start();

			// Ignore traps for hover creatures, unless this is the last hex
			let enterHexOpts = $j.extend({
				ignoreTraps: creature.movementType() !== "normal" && hexId < path.length - 1
			}, opts);

			tween.onComplete.add(() => {
				if (creature.dead) {
					// Stop moving if creature has died while moving
					this.movementComplete(creature, hex, anim_id, opts);
					return;
				}

				// Sound Effect
				game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

				if (!opts.ignoreMovementPoint) {
					creature.remainingMove--;

					if (opts.customMovementPoint === 0) {
						creature.travelDist++;
					}
				}

				this.enterHex(creature, hex, enterHexOpts);

				anim(); // Next tween
			});

			hexId++;
		}.bind(this);

		anim();
	}

	fly(creature, path, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			path = path.slice(0, opts.customMovementPoint);
			// For compatibility
			this.movementPoints = creature.remainingMove;
			creature.remainingMove = opts.customMovementPoint;
		}

		game.freezedInput = true;

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		let hexId = 0;

		creature.healthHide();

		let hex = path[0];

		let start = game.grid.hexes[creature.y][creature.x - creature.size + 1];
		let currentHex = game.grid.hexes[hex.y][hex.x - creature.size + 1];

		this.leaveHex(creature, start, opts);

		let speed = !opts.overrideSpeed ? creature.animation.walk_speed : opts.overrideSpeed;

		let tween = game.Phaser.add.tween(creature.grp)
			.to(currentHex.displayPos, parseInt(speed), Phaser.Easing.Linear.None)
			.start();

		tween.onComplete.add(() => {
			// Sound Effect
			game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

			if (!opts.ignoreMovementPoint) {
				// Determine distance
				let distance = 0;
				let k = 0;
				while (!distance && start != currentHex) {
					k++;

					if (arrayUtils.findPos(start.adjacentHex(k), currentHex)) {
						distance = k;
					}
				}

				creature.remainingMove -= distance;
				if (opts.customMovementPoint === 0) {
					creature.travelDist += distance;
				}
			}

			this.enterHex(creature, hex, opts);
			this.movementComplete(creature, hex, anim_id, opts);
			return;
		});
	}

	teleport(creature, path, opts) {
		let game = this.game,
			hex = path[0],
			currentHex = game.grid.hexes[hex.y][hex.x - creature.size + 1];

		this.leaveHex(creature, currentHex, opts);

		let anim_id = Math.random();
		game.animationQueue.push(anim_id);

		// FadeOut
		let tween = game.Phaser.add.tween(creature.grp)
			.to({
				alpha: 0
			}, 500, Phaser.Easing.Linear.None)
			.start();

		tween.onComplete.add(() => {
			// Sound Effect
			game.soundsys.playSound(game.soundLoaded[0], game.soundsys.effectsGainNode);

			// position
			creature.grp.x = currentHex.displayPos.x;
			creature.grp.y = currentHex.displayPos.y;

			// FadeIn
			let tween = game.Phaser.add.tween(creature.grp)
				.to({
					alpha: 1
				}, 500, Phaser.Easing.Linear.None)
				.start();

			this.enterHex(creature, hex, opts);
			this.movementComplete(creature, hex, anim_id, opts);
			return;
		});
	}

	push(creature, path, opts) {
		opts.pushed = true;
		this.walk(creature, path, opts);
	}

	//--------Special Functions---------//

	enterHex(creature, hex, opts) {
		let game = this.game;

		creature.cleanHex();
		creature.x = hex.x - 0;
		creature.y = hex.y - 0;
		creature.pos = hex.pos;
		creature.updateHex();

		game.onStepIn(creature, hex, opts);

		creature.pickupDrop();

		opts.callbackStepIn(hex);

		game.grid.orderCreatureZ();
	}

	leaveHex(creature, hex, opts) {
		let game = this.game;

		if (!opts.pushed) {
			creature.faceHex(hex, creature.hexagons[0]); // Determine facing
		}

		game.onStepOut(creature, creature.hexagons[0]); // Trigger
		game.grid.orderCreatureZ();
	}

	movementComplete(creature, hex, anim_id, opts) {
		let game = this.game;

		if (opts.customMovementPoint > 0) {
			creature.remainingMove = this.movementPoints;
		}

		game.grid.updateDisplay();
		// TODO: Turn around animation
		if (opts.turnAroundOnComplete) {
			creature.facePlayerDefault();
		}

		// TODO: Reveal health indicator
		creature.healthShow();

		game.onCreatureMove(creature, hex); // Trigger

		creature.hexagons.forEach((hex) => {
			hex.pickupDrop(creature);
		});

		game.grid.orderCreatureZ();

		let queue = game.animationQueue.filter((item) => item != anim_id);

		if (queue.length === 0) {
			game.freezedInput = false;
		}

		game.animationQueue = queue;
	}

	projectile(this_2, target, sprite_id, path, args, start_x, start_y) {
		let game = this.game,
			dist = arrayUtils.filterCreature(path.slice(0), false, false).length,
			emissionPoint = {
				x: this_2.creature.grp.x + start_x,
				y: this_2.creature.grp.y + start_y
			},
			targetPoint = {
				x: target.grp.x + 52,
				y: target.grp.y - 20
			},
			// Sprite id here
			sprite = game.grid.creatureGroup.create(emissionPoint.x, emissionPoint.y, sprite_id),
			duration = dist * 75;

		sprite.anchor.setTo(0.5);
		sprite.rotation = -Math.PI / 3 + args.direction * Math.PI / 3;
		let tween = game.Phaser.add.tween(sprite)
			.to({
				x: targetPoint.x,
				y: targetPoint.y
			}, duration, Phaser.Easing.Linear.None)
			.start();

		return [tween, sprite, dist];
	}
}
<|endoftext|>


<commit_before>var markdown = require('node-markdown').Markdown;
var crypto = require('crypto');
var pad = require('./utils').pad;

var months;
var days;

module.exports.months = months = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
];

module.exports.days = days = [
  'Sunday',
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday',
];

module.exports.markdown = function(str) {
  return markdown(str);
};

module.exports.summary = function(body, separator, trimmer) {
  separator = '<!-- more -->';
  trimmer = trimmer || '…';
  return body.split(separator)[0].replace(/\.$/, trimmer);
};

module.exports.gravatar = function (email, size) {
  size = size || 50;
  return 'http://www.gravatar.com/avatar/' +
         crypto.createHash('md5').update(email.trim().toLowerCase()).digest('hex') +
         '?r=pg&s=#{size}.jpg&d=identicon';
};

module.exports.prettyDate = function (date) {
  return months[date.getUTCMonth()] + ' ' + date.getUTCDate() + ', ' + date.getUTCFullYear();
};

module.exports.isoDate = function (date) {
  return date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate());
};

module.exports.rfc822Date = function (date) {
  return days[date.getUTCDay()].substring(0, 3) + ', ' +
         pad(date.getUTCDate()) + ' ' +
         months[date.getUTCMonth()].substring(0, 3) + ' ' +
         date.getUTCFullYear() + ' ' +
         pad(date.getUTCHours()) + ':' +
         pad(date.getUTCMinutes()) + ':' +
         pad(date.getUTCSeconds()) + ' ' + 'GMT';
};<commit_msg>Fixed gravatar helper, size was invalid<commit_after>var markdown = require('node-markdown').Markdown;
var crypto = require('crypto');
var pad = require('./utils').pad;

var months;
var days;

module.exports.months = months = [
  'January',
  'February',
  'March',
  'April',
  'May',
  'June',
  'July',
  'August',
  'September',
  'October',
  'November',
  'December'
];

module.exports.days = days = [
  'Sunday',
  'Monday',
  'Tuesday',
  'Wednesday',
  'Thursday',
  'Friday',
  'Saturday',
];

module.exports.markdown = function(str) {
  return markdown(str);
};

module.exports.summary = function(body, separator, trimmer) {
  separator = '<!-- more -->';
  trimmer = trimmer || '…';
  return body.split(separator)[0].replace(/\.$/, trimmer);
};

module.exports.gravatar = function (email, size) {
  size = size || 50;
  return 'http://www.gravatar.com/avatar/' +
         crypto.createHash('md5').update(email.trim().toLowerCase()).digest('hex') +
         '?r=pg&s=' + Number(size) + '.jpg&d=identicon';
};

module.exports.prettyDate = function (date) {
  return months[date.getUTCMonth()] + ' ' + date.getUTCDate() + ', ' + date.getUTCFullYear();
};

module.exports.isoDate = function (date) {
  return date.getUTCFullYear() + '-' + pad(date.getUTCMonth() + 1) + '-' + pad(date.getUTCDate());
};

module.exports.rfc822Date = function (date) {
  return days[date.getUTCDay()].substring(0, 3) + ', ' +
         pad(date.getUTCDate()) + ' ' +
         months[date.getUTCMonth()].substring(0, 3) + ' ' +
         date.getUTCFullYear() + ' ' +
         pad(date.getUTCHours()) + ':' +
         pad(date.getUTCMinutes()) + ':' +
         pad(date.getUTCSeconds()) + ' ' + 'GMT';
};<|endoftext|>


<commit_before>import 'jquery-ui/themes/base/core.css';
import 'jquery-ui/themes/base/accordion.css';
import 'jquery-ui/themes/base/autocomplete.css';
import 'jquery-ui/themes/base/button.css';
import 'jquery-ui/themes/base/checkboxradio.css';
import 'jquery-ui/themes/base/controlgroup.css';
import 'jquery-ui/themes/base/datepicker.css';
import 'jquery-ui/themes/base/dialog.css';
import 'jquery-ui/themes/base/draggable.css';
import 'jquery-ui/themes/base/menu.css';
import 'jquery-ui/themes/base/progressbar.css';
import 'jquery-ui/themes/base/resizable.css';
import 'jquery-ui/themes/base/selectable.css';
import 'jquery-ui/themes/base/selectmenu.css';
import 'jquery-ui/themes/base/sortable.css';
import 'jquery-ui/themes/base/slider.css';
import 'jquery-ui/themes/base/spinner.css';
import 'jquery-ui/themes/base/tabs.css';
import 'jquery-ui/themes/base/tooltip.css';
import 'jquery-ui/themes/base/theme.css';
<commit_msg>Only include the jquery-ui css files that are used<commit_after>import 'jquery-ui/themes/base/core.css';
// import 'jquery-ui/themes/base/accordion.css';
// import 'jquery-ui/themes/base/autocomplete.css';
// import 'jquery-ui/themes/base/button.css';
// import 'jquery-ui/themes/base/checkboxradio.css';
// import 'jquery-ui/themes/base/controlgroup.css';
import 'jquery-ui/themes/base/datepicker.css';
// import 'jquery-ui/themes/base/dialog.css';
import 'jquery-ui/themes/base/draggable.css';
// import 'jquery-ui/themes/base/menu.css';
// import 'jquery-ui/themes/base/progressbar.css';
import 'jquery-ui/themes/base/resizable.css';
// import 'jquery-ui/themes/base/selectable.css';
// import 'jquery-ui/themes/base/selectmenu.css';
// import 'jquery-ui/themes/base/sortable.css';
import 'jquery-ui/themes/base/slider.css';
// import 'jquery-ui/themes/base/spinner.css';
// import 'jquery-ui/themes/base/tabs.css';
// import 'jquery-ui/themes/base/tooltip.css';
import 'jquery-ui/themes/base/theme.css';
<|endoftext|>


<commit_before>import React from 'react';
import Router from 'react-router';
import routes from './views/routes';
import { Provider } from 'react-redux';

const getFetchData = (component={}) => {
  return component.DecoratedComponent ?
    getFetchData(component.DecoratedComponent) :
    component.fetchData;
};

export function createTransitionHook(store) {
  return (nextState, transition, callback) => {
    Promise.all(nextState.branch
      .map(route => route.component)
      .filter(getFetchData(component))
      .map(getFetchData)
      .map(fetchData => fetchData(store, nextState.params))
      .then(() => {
        callback(); // can't just pass callback to then() because callback assumes first param is error
      }, (error) => {
        callback(error);
      });
  };
}

export default function universalRouter(location, history, store) {
  return new Promise((resolve, reject) => {
    Router.run(routes, location, [createTransitionHook(store)], (error, initialState, transition) => {
      if (error) {
        return reject(error);
      }

      if (transition && transition.redirectInfo) {
        return resolve({
          transition,
          isRedirect: true
        });
      }

      if (history) {  // only on client side
        initialState.history = history;
      }

      const component = (
        <Provider store={store} key="provider">
          {() => <Router {...initialState} children={routes}/>}
        </Provider>
      );

      return resolve({
        component,
        isRedirect: false
      });
    });
  });
}
<commit_msg>incorporated PR #67 and added some comments to promise chaining in createTransitionHook()<commit_after>import React from 'react';
import Router from 'react-router';
import routes from './views/routes';
import { Provider } from 'react-redux';

const getFetchData = (component={}) => {
  return component.DecoratedComponent ?
    getFetchData(component.DecoratedComponent) :
    component.fetchData;
};

export function createTransitionHook(store) {
  return (nextState, transition, callback) => {
    const promises = nextState.branch
      .map(route => route.component)                          // pull out individual route components
      .filter((component) => getFetchData(component))         // only look at ones with a static fetchData()
      .map(getFetchData)                                      // pull out fetch data methods
      .map(fetchData => fetchData(store, nextState.params));  // call fetch data methods and save promises
    Promise.all(promises)
      .then(() => {
        callback(); // can't just pass callback to then() because callback assumes first param is error
      }, (error) => {
        callback(error);
      });
  };
}

export default function universalRouter(location, history, store) {
  return new Promise((resolve, reject) => {
    Router.run(routes, location, [createTransitionHook(store)], (error, initialState, transition) => {
      if (error) {
        return reject(error);
      }

      if (transition && transition.redirectInfo) {
        return resolve({
          transition,
          isRedirect: true
        });
      }

      if (history) {  // only on client side
        initialState.history = history;
      }

      const component = (
        <Provider store={store} key="provider">
          {() => <Router {...initialState} children={routes}/>}
        </Provider>
      );

      return resolve({
        component,
        isRedirect: false
      });
    });
  });
}
<|endoftext|>


<commit_before>/**
 * A utility class to help make it easier to access the data stores
 * @extends {Map}
 */
class Collection extends Map {
  constructor(iterable) {
    super(iterable);
    this._array = null;
    this._keyArray = null;
  }

  set(key, val) {
    super.set(key, val);
    this._array = null;
    this._keyArray = null;
  }

  delete(key) {
    super.delete(key);
    this._array = null;
    this._keyArray = null;
  }

  /**
   * Creates an ordered array of the values of this collection, and caches it internally. The array will only be
   * reconstructed if an item is added to or removed from the collection, or if you add/remove elements on the array.
   * @returns {Array}
   * @example
   * // identical to:
   * Array.from(collection.values());
   */
  array() {
    if (!this._array || this._array.length !== this.size) this._array = Array.from(this.values());
    return this._array;
  }

  /**
   * Creates an ordered array of the keys of this collection, and caches it internally. The array will only be
   * reconstructed if an item is added to or removed from the collection, or if you add/remove elements on the array.
   * @returns {Array}
   * @example
   * // identical to:
   * Array.from(collection.keys());
   */
  keyArray() {
    if (!this._keyArray || this._keyArray.length !== this.size) this._keyArray = Array.from(this.keys());
    return this._keyArray;
  }

  /**
   * Returns the first item in this collection.
   * @returns {*}
   */
  first() {
    return this.values().next().value;
  }

  /**
   * Returns the first key in this collection.
   * @returns {*}
   */
  firstKey() {
    return this.keys().next().value;
  }

  /**
   * Returns the last item in this collection. This is a relatively slow operation,
   * since an array copy of the values must be made to find the last element.
   * @returns {*}
   */
  last() {
    const arr = this.array();
    return arr[arr.length - 1];
  }

  /**
   * Returns the last key in this collection. This is a relatively slow operation,
   * since an array copy of the keys must be made to find the last element.
   * @returns {*}
   */
  lastKey() {
    const arr = this.keyArray();
    return arr[arr.length - 1];
  }

  /**
   * Returns a random item from this collection. This is a relatively slow operation,
   * since an array copy of the values must be made to find a random element.
   * @returns {*}
   */
  random() {
    const arr = this.array();
    return arr[Math.floor(Math.random() * arr.length)];
  }

  /**
   * Returns a random key from this collection. This is a relatively slow operation,
   * since an array copy of the keys must be made to find a random element.
   * @returns {*}
   */
  randomKey() {
    const arr = this.keyArray();
    return arr[Math.floor(Math.random() * arr.length)];
  }

  /**
   * Returns an array of items where `item[prop] === value` of the collection
   * @param {string} prop The property to test against
   * @param {*} value The expected value
   * @returns {array}
   * @example
   * collection.findAll('username', 'Bob');
   */
  findAll(prop, value) {
    if (typeof prop !== 'string') throw new TypeError('Key must be a string.');
    if (typeof value === 'undefined') throw new Error('Value must be specified.');
    const results = [];
    for (const item of this.values()) {
      if (item[prop] === value) results.push(item);
    }
    return results;
  }

  /**
   * Returns a single item where `item[prop] === value`, or the given function returns `true`.
   * In the latter case, this is identical to
   * [Array.find()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
   * @param {string|function} propOrFn The property to test against, or the function to test with
   * @param {*} [value] The expected value - only applicable and required if using a property for the first argument
   * @returns {*}
   * @example
   * collection.find('username', 'Bob');
   * @example
   * collection.find(val => val.username === 'Bob');
   */
  find(propOrFn, value) {
    if (typeof propOrFn === 'string') {
      if (typeof value === 'undefined') throw new Error('Value must be specified.');
      for (const item of this.values()) {
        if (item[propOrFn] === value) return item;
      }
      return null;
    } else if (typeof propOrFn === 'function') {
      for (const [key, val] of this) {
        if (propOrFn(val, key, this)) return val;
      }
      return null;
    } else {
      throw new Error('First argument must be a property string or a function.');
    }
  }

  /* eslint-disable max-len */
  /**
   * Returns the key of the item where `item[prop] === value`, or the given function returns `true`.
   * In the latter case, this is identical to
   * [Array.findIndex()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex).
   * @param {string|function} propOrFn The property to test against, or the function to test with
   * @param {*} [value] The expected value - only applicable and required if using a property for the first argument
   * @returns {*}
   * @example
   * collection.findKey('username', 'Bob');
   * @example
   * collection.findKey(val => val.username === 'Bob');
   */
  /* eslint-enable max-len */
  findKey(propOrFn, value) {
    if (typeof propOrFn === 'string') {
      if (typeof value === 'undefined') throw new Error('Value must be specified.');
      for (const [key, val] of this) {
        if (val[propOrFn] === value) return key;
      }
      return null;
    } else if (typeof propOrFn === 'function') {
      for (const [key, val] of this) {
        if (propOrFn(val, key, this)) return key;
      }
      return null;
    } else {
      throw new Error('First argument must be a property string or a function.');
    }
  }

  /**
   * Returns true if the collection has an item where `item[prop] === value`
   * @param {string} prop The property to test against
   * @param {*} value The expected value
   * @returns {boolean}
   * @example
   * if (collection.exists('username', 'Bob')) {
   *  console.log('user here!');
   * }
   */
  exists(prop, value) {
    return Boolean(this.find(prop, value));
  }

  /**
   * Identical to
   * [Array.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter),
   * but returns a Collection instead of an Array.
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {Collection}
   */
  filter(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    const collection = new Collection();
    for (const [key, val] of this) {
      if (fn(val, key, this)) collection.set(key, val);
    }
    return collection;
  }

  /**
   * Identical to
   * [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
   * @param {function} fn Function that produces an element of the new array, taking three arguments
   * @param {*} [thisArg] Value to use as `this` when executing function
   * @returns {array}
   */
  map(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    const arr = new Array(this.size);
    let i = 0;
    for (const [key, val] of this) arr[i++] = fn(val, key, this);
    return arr;
  }

  /**
   * Identical to
   * [Array.some()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some).
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {boolean}
   */
  some(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    for (const [key, val] of this) {
      if (fn(val, key, this)) return true;
    }
    return false;
  }

  /**
   * Identical to
   * [Array.every()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every).
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {boolean}
   */
  every(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    for (const [key, val] of this) {
      if (!fn(val, key, this)) return false;
    }
    return true;
  }

  /**
   * Identical to
   * [Array.reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce).
   * @param {function} fn Function used to reduce
   * @param {*} [startVal] The starting value
   * @returns {*}
   */
  reduce(fn, startVal) {
    let currentVal = startVal;
    for (const [key, val] of this) currentVal = fn(currentVal, val, key, this);
    return currentVal;
  }

  /**
   * Combines this collection with others into a new collection. None of the source collections are modified.
   * @param {Collection} collections Collections to merge
   * @returns {Collection}
   * @example const newColl = someColl.concat(someOtherColl, anotherColl, ohBoyAColl);
   */
  concat(...collections) {
    const newColl = new this.constructor();
    for (const [key, val] of this) newColl.set(key, val);
    for (const coll of collections) {
      for (const [key, val] of coll) newColl.set(key, val);
    }
    return newColl;
  }

  /**
   * If the items in this collection have a delete method (e.g. messages), invoke
   * the delete method. Returns an array of promises
   * @returns {Promise[]}
   */
  deleteAll() {
    const returns = [];
    for (const item of this.values()) {
      if (item.delete) returns.push(item.delete());
    }
    return returns;
  }
}

module.exports = Collection;
<commit_msg>Add Collection.filterArray<commit_after>/**
 * A utility class to help make it easier to access the data stores
 * @extends {Map}
 */
class Collection extends Map {
  constructor(iterable) {
    super(iterable);
    this._array = null;
    this._keyArray = null;
  }

  set(key, val) {
    super.set(key, val);
    this._array = null;
    this._keyArray = null;
  }

  delete(key) {
    super.delete(key);
    this._array = null;
    this._keyArray = null;
  }

  /**
   * Creates an ordered array of the values of this collection, and caches it internally. The array will only be
   * reconstructed if an item is added to or removed from the collection, or if you add/remove elements on the array.
   * @returns {Array}
   * @example
   * // identical to:
   * Array.from(collection.values());
   */
  array() {
    if (!this._array || this._array.length !== this.size) this._array = Array.from(this.values());
    return this._array;
  }

  /**
   * Creates an ordered array of the keys of this collection, and caches it internally. The array will only be
   * reconstructed if an item is added to or removed from the collection, or if you add/remove elements on the array.
   * @returns {Array}
   * @example
   * // identical to:
   * Array.from(collection.keys());
   */
  keyArray() {
    if (!this._keyArray || this._keyArray.length !== this.size) this._keyArray = Array.from(this.keys());
    return this._keyArray;
  }

  /**
   * Returns the first item in this collection.
   * @returns {*}
   */
  first() {
    return this.values().next().value;
  }

  /**
   * Returns the first key in this collection.
   * @returns {*}
   */
  firstKey() {
    return this.keys().next().value;
  }

  /**
   * Returns the last item in this collection. This is a relatively slow operation,
   * since an array copy of the values must be made to find the last element.
   * @returns {*}
   */
  last() {
    const arr = this.array();
    return arr[arr.length - 1];
  }

  /**
   * Returns the last key in this collection. This is a relatively slow operation,
   * since an array copy of the keys must be made to find the last element.
   * @returns {*}
   */
  lastKey() {
    const arr = this.keyArray();
    return arr[arr.length - 1];
  }

  /**
   * Returns a random item from this collection. This is a relatively slow operation,
   * since an array copy of the values must be made to find a random element.
   * @returns {*}
   */
  random() {
    const arr = this.array();
    return arr[Math.floor(Math.random() * arr.length)];
  }

  /**
   * Returns a random key from this collection. This is a relatively slow operation,
   * since an array copy of the keys must be made to find a random element.
   * @returns {*}
   */
  randomKey() {
    const arr = this.keyArray();
    return arr[Math.floor(Math.random() * arr.length)];
  }

  /**
   * Returns an array of items where `item[prop] === value` of the collection
   * @param {string} prop The property to test against
   * @param {*} value The expected value
   * @returns {array}
   * @example
   * collection.findAll('username', 'Bob');
   */
  findAll(prop, value) {
    if (typeof prop !== 'string') throw new TypeError('Key must be a string.');
    if (typeof value === 'undefined') throw new Error('Value must be specified.');
    const results = [];
    for (const item of this.values()) {
      if (item[prop] === value) results.push(item);
    }
    return results;
  }

  /**
   * Returns a single item where `item[prop] === value`, or the given function returns `true`.
   * In the latter case, this is identical to
   * [Array.find()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find).
   * @param {string|function} propOrFn The property to test against, or the function to test with
   * @param {*} [value] The expected value - only applicable and required if using a property for the first argument
   * @returns {*}
   * @example
   * collection.find('username', 'Bob');
   * @example
   * collection.find(val => val.username === 'Bob');
   */
  find(propOrFn, value) {
    if (typeof propOrFn === 'string') {
      if (typeof value === 'undefined') throw new Error('Value must be specified.');
      for (const item of this.values()) {
        if (item[propOrFn] === value) return item;
      }
      return null;
    } else if (typeof propOrFn === 'function') {
      for (const [key, val] of this) {
        if (propOrFn(val, key, this)) return val;
      }
      return null;
    } else {
      throw new Error('First argument must be a property string or a function.');
    }
  }

  /* eslint-disable max-len */
  /**
   * Returns the key of the item where `item[prop] === value`, or the given function returns `true`.
   * In the latter case, this is identical to
   * [Array.findIndex()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex).
   * @param {string|function} propOrFn The property to test against, or the function to test with
   * @param {*} [value] The expected value - only applicable and required if using a property for the first argument
   * @returns {*}
   * @example
   * collection.findKey('username', 'Bob');
   * @example
   * collection.findKey(val => val.username === 'Bob');
   */
  /* eslint-enable max-len */
  findKey(propOrFn, value) {
    if (typeof propOrFn === 'string') {
      if (typeof value === 'undefined') throw new Error('Value must be specified.');
      for (const [key, val] of this) {
        if (val[propOrFn] === value) return key;
      }
      return null;
    } else if (typeof propOrFn === 'function') {
      for (const [key, val] of this) {
        if (propOrFn(val, key, this)) return key;
      }
      return null;
    } else {
      throw new Error('First argument must be a property string or a function.');
    }
  }

  /**
   * Returns true if the collection has an item where `item[prop] === value`
   * @param {string} prop The property to test against
   * @param {*} value The expected value
   * @returns {boolean}
   * @example
   * if (collection.exists('username', 'Bob')) {
   *  console.log('user here!');
   * }
   */
  exists(prop, value) {
    return Boolean(this.find(prop, value));
  }

  /**
   * Identical to
   * [Array.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter),
   * but returns a Collection instead of an Array.
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {Collection}
   */
  filter(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    const results = new Collection();
    for (const [key, val] of this) {
      if (fn(val, key, this)) results.set(key, val);
    }
    return results;
  }

  /**
   * Identical to
   * [Array.filter()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter).
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {Collection}
   */
  filterArray(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    const results = [];
    for (const [key, val] of this) {
      if (fn(val, key, this)) results.push(val);
    }
    return results;
  }

  /**
   * Identical to
   * [Array.map()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map).
   * @param {function} fn Function that produces an element of the new array, taking three arguments
   * @param {*} [thisArg] Value to use as `this` when executing function
   * @returns {array}
   */
  map(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    const arr = new Array(this.size);
    let i = 0;
    for (const [key, val] of this) arr[i++] = fn(val, key, this);
    return arr;
  }

  /**
   * Identical to
   * [Array.some()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some).
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {boolean}
   */
  some(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    for (const [key, val] of this) {
      if (fn(val, key, this)) return true;
    }
    return false;
  }

  /**
   * Identical to
   * [Array.every()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/every).
   * @param {function} fn Function used to test (should return a boolean)
   * @param {Object} [thisArg] Value to use as `this` when executing function
   * @returns {boolean}
   */
  every(fn, thisArg) {
    if (thisArg) fn = fn.bind(thisArg);
    for (const [key, val] of this) {
      if (!fn(val, key, this)) return false;
    }
    return true;
  }

  /**
   * Identical to
   * [Array.reduce()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce).
   * @param {function} fn Function used to reduce
   * @param {*} [startVal] The starting value
   * @returns {*}
   */
  reduce(fn, startVal) {
    let currentVal = startVal;
    for (const [key, val] of this) currentVal = fn(currentVal, val, key, this);
    return currentVal;
  }

  /**
   * Combines this collection with others into a new collection. None of the source collections are modified.
   * @param {Collection} collections Collections to merge
   * @returns {Collection}
   * @example const newColl = someColl.concat(someOtherColl, anotherColl, ohBoyAColl);
   */
  concat(...collections) {
    const newColl = new this.constructor();
    for (const [key, val] of this) newColl.set(key, val);
    for (const coll of collections) {
      for (const [key, val] of coll) newColl.set(key, val);
    }
    return newColl;
  }

  /**
   * If the items in this collection have a delete method (e.g. messages), invoke
   * the delete method. Returns an array of promises
   * @returns {Promise[]}
   */
  deleteAll() {
    const returns = [];
    for (const item of this.values()) {
      if (item.delete) returns.push(item.delete());
    }
    return returns;
  }
}

module.exports = Collection;
<|endoftext|>


<commit_before>function consume(ev) { return false; }

function Tab(tabdb, title, favIconUrl) {
  this.parent = null;
  this.tabdb = tabdb;
  this.elem = $('

')
    .attr('class','mtab').attr('id','tab_'+tabdb.tid)
    .css({
      'height' : UI.TAB_HEIGHT+'px',
      'padding' : UI.TAB_PADDING+'px'
    });
  var elem = this.elem;

  this.nodeicon = $('').attr('class', 'node')
                .css({
                  'height' : UI.TAB_NODE_DIM+'px',
                  'width' : UI.TAB_NODE_DIM+'px',
                  'marginTop' : UI.TAB_NODE_MARGIN_TOP+'px',
                  'marginBottom' : UI.TAB_NODE_MARGIN_BOTTOM+'px'
                });
  this.setNodeIcon();
  this.elem.append(this.nodeicon);

  var favicon = $('').attr('class','favicon')
                .css({
                  'height' : UI.TAB_IMG_DIM+'px',
                  'width' : UI.TAB_IMG_DIM+'px',
                  'margin' : UI.TAB_IMG_MARGIN+'px'
                });
  if(favIconUrl) {
    favicon.attr('src', favIconUrl);
  } else if(tabdb.faviconurl) {
    favicon.attr('src', tabdb.faviconurl);
  } else {
    favicon.attr('src', Tab.fallbackIcon);
  }
  this.elem.append(favicon);

  this.staricon = $('').attr('class','star')
                .css({
                  'height' : UI.TAB_IMG_DIM+'px',
                  'width' : UI.TAB_IMG_DIM+'px',
                  'margin' : UI.TAB_IMG_MARGIN+'px'
                });
  if(Fav.is(tabdb.url)) {
    this.staricon.attr('src', Tab.starOn);
  } else {
    this.staricon.attr('src', Tab.starOff);
  }
  this.elem.append(this.staricon);

  this.staricon.hide();
  this.staricon.click(Tab.toggleFav).mousedown(consume).mouseup(consume);

  if(title) {
    rtabtitle = $('

').attr('class','title').text(title);
  } else {
    rtabtitle = $('

').attr('class','title').text(tabdb.title);
  }
  rtabtitle.css('padding-top', UI.TAB_TITLE_PADDING_TOP+'px');

  var tab = this;
  if(inPopup) {
    rtabtitle.mousedown(Tab.selectTab)
      .mouseup(consume).mousemove(consume);
  } else {
    this.elem.mousedown(function(ev) { tab.pick(ev); });
    $(document).mousemove(function(ev) { tab.drag(ev); });
    $(document).mouseup(function(ev) { tab.drop(ev); });
  }

  $('.node', this.elem).click(function(){
      tab.parent.toggleTree(tab);
      tab.setNodeIcon();
    }).mousedown(consume).mouseup(consume).mousemove(consume);
  $('.favicon', this.elem).click(Tab.selectTab)
    .mousedown(consume).mouseup(consume).mousemove(consume);

  this.elem.mouseenter(Tab.mouseenter);
  this.elem.mouseleave(Tab.mouseleave);

  this.elem.append(rtabtitle);

  this.elem.css({
    'margin-left' : (UI.DEPTH_STEP*tabdb.depth)+'px',
    'width' : (UI.winw-50-UI.DEPTH_STEP*tabdb.depth)+'px'
  });
  var wcorr = 30 + UI.scale * 10;
  $('div', this.elem).css({
    'width' : (UI.winw-140-wcorr-UI.DEPTH_STEP*tabdb.depth)+'px'
  });
    //$('.mtab', this.elem).css({'width': (UI.winw-50)+'px'})
    //$('.mtab > div', this.elem).css({'width': (UI.winw-140)+'px'})
}

Tab.fallbackIcon = chrome.extension.getURL('images/icon28.png');
Tab.starOn = chrome.extension.getURL('images/favon.png');
Tab.starOff = chrome.extension.getURL('images/favoff.png');
Tab.collapsedIcon = chrome.extension.getURL('images/collapsed.png');
Tab.expandedIcon = chrome.extension.getURL('images/expanded.png');
Tab.leafIcon = chrome.extension.getURL('images/leaf.png');

Tab.selectTab = function() {
  var match = /tab_(\d+)/.exec($(this).parent().attr('id'));
  if(match && match[1]) {
    chrome.tabs.update(parseInt(match[1]), {selected : true});
  }
  return false;
}

Tab.toggleFav = function() {
  var p = $(this).parent();
  var match = /tab_(\d+)/.exec(p.attr('id'));
  if(match && match[1]) {
    var tab = UI.tMap[parseInt(match[1])];
    if(Fav.is(tab.tabdb.url)) {
      Fav.remove(tab.tabdb.url);
      $(this).attr('src', Tab.starOff);
    } else {
      var fi = $(this).siblings('.favicon');
      Fav.add(tab.tabdb.url, fi.attr('src'));
      $(this).attr('src', Tab.starOn);
    }
    refresh_favorites();
  } else {
    alert('Error recognizing the tab');
  }
  return false;
}

Tab.mouseenter = function(ev) {
  $('.star', $(this)).show();
},

Tab.mouseleave = function(ev) {
  $('.star', $(this)).hide();
}

Tab.prototype = {
  setNodeIcon : function() {
    if(this.tabdb.isparent) {
      if(this.tabdb.collapsed) {
        this.nodeicon.attr('src', Tab.collapsedIcon);
      } else {
        this.nodeicon.attr('src', Tab.expandedIcon);
      }
    } else {
      this.nodeicon.attr('src', Tab.leafIcon);
    }
  },

  pick : function(ev) {
    var wframe = this.parent;
    this.carrier = wframe.removeTabSubtree(this);
    wframe.refreshStyle();
    UI.relayout_column(UI.get_column(ev.clientX));
    this.carrier.css({
      'position':'absolute',
      'top' : (ev.clientY-15)+'px',
      'left' : (ev.clientX - UI.winw/2)+'px',
      'width' : UI.winw+'px'
      });
    this.inTransit = true;
  },
  /*
  pick : function(ev) {
    this.reset_depth();

    this.detach(ev.clientY-15, ev.clientX - UI.winw/2);
    var wframe = this.parent;
    wframe.removeTab(this);
    wframe.refreshStyle();

    UI.relayout_column(UI.get_column(ev.clientX));
  },
  */

  detach : function(top, left) {
    this.elem.css({
      'position':'absolute',
      'top' : top+'px',
      'left' : left+'px',
      '-webkit-box-shadow' : 'rgba(20,20,20,1) 1px 1px 5px'
      });
    this.inTransit = true;
  },

  drag : function(ev) {
    if(this.inTransit) {
      //this.elem.css({
      this.carrier.css({
        'top' : (ev.clientY - 15)+'px',
        'left' : (ev.clientX - UI.winw/2)+'px'
      });
    }
  },

  attach : function() {
    this.inTransit = false;

    this.elem.css({
      'position':'relative',
      '-webkit-box-shadow' : null,
      'top': null,
      'left': null
    });
  },

  reset_depth : function() {
    this.elem.css({
      'margin-left' : '0px',
      'width' : (UI.winw-50)+'px'
    });
    var wcorr = 30 + UI.scale * 10;
    $('div', this.elem).css({
      'width' : (UI.winw-140-wcorr-UI.DEPTH_STEP*this.tabdb.depth)+'px'
    });
  },

  drop : function(ev) {
    if(!this.inTransit) return;

    // Check on which window are we dropping
    for(i in UI.wMap) {
      var win = UI.wMap[i];
      if(!win) continue; // for removed windows
      if(win.contains(ev.clientX, ev.clientY)) {

        //this.attach();
        //win.addTab(this);
        tidlist = win.addTabSubtree(this.carrier);

        win.refreshStyle();

        UI.relayout_column(UI.get_column(ev.clientX));

        bgport.postMessage({
          name : 'tabmove',
          tidlist : tidlist,
          wid : win.windb.wid
        });
        return;
      }
    }

    this.inTransit = false;
    this.elem.remove();

    bgport.postMessage({
      name : 'tabmovenew',
      tid : this.tabdb.tid,
    });
    /*
    // Not dropped on a window, create a new one
    var thistab = this;
    var dropcol = get_column(ev.clientX);

    function removeAllButThisTab(tabs) {
      for(var i=0; i < tabs.length; i++) {
        if(tabs[i].id != thistab.tabdb.tid) {
          chrome.tabs.remove(tabs[i].id);
        }
      }

    }
    */

    /*
    chrome.windows.create(null,
      function(win) {

        var wf = new WinFrame(win);
        windowMap[win.id] = wf;
        windowList.push(wf);

        $('body').append(wf.elem);
        wf.addTab(thistab);
        wf.refreshStyle();
        winColumns[dropcol].push(wf);
        relayout_column(dropcol);

        chrome.tabs.move(thistab.tabdb.tid,
          { windowId : win.id, index:0 },
          function() {
            chrome.tabs.getAllInWindow(
              win.id, removeAllButThisTab);
          });
      }
    );
    */
  },
}

<commit_msg>cleanup<commit_after>function consume(ev) { return false; }

function Tab(tabdb, title, favIconUrl) {
  this.parent = null;
  this.tabdb = tabdb;
  this.elem = $('

')
    .attr('class','mtab').attr('id','tab_'+tabdb.tid)
    .css({
      'height' : UI.TAB_HEIGHT+'px',
      'padding' : UI.TAB_PADDING+'px'
    });
  var elem = this.elem;

  this.nodeicon = $('').attr('class', 'node')
                .css({
                  'height' : UI.TAB_NODE_DIM+'px',
                  'width' : UI.TAB_NODE_DIM+'px',
                  'marginTop' : UI.TAB_NODE_MARGIN_TOP+'px',
                  'marginBottom' : UI.TAB_NODE_MARGIN_BOTTOM+'px'
                });
  this.setNodeIcon();
  this.elem.append(this.nodeicon);

  var favicon = $('').attr('class','favicon')
                .css({
                  'height' : UI.TAB_IMG_DIM+'px',
                  'width' : UI.TAB_IMG_DIM+'px',
                  'margin' : UI.TAB_IMG_MARGIN+'px'
                });
  if(favIconUrl) {
    favicon.attr('src', favIconUrl);
  } else if(tabdb.faviconurl) {
    favicon.attr('src', tabdb.faviconurl);
  } else {
    favicon.attr('src', Tab.fallbackIcon);
  }
  this.elem.append(favicon);

  this.staricon = $('').attr('class','star')
                .css({
                  'height' : UI.TAB_IMG_DIM+'px',
                  'width' : UI.TAB_IMG_DIM+'px',
                  'margin' : UI.TAB_IMG_MARGIN+'px'
                });
  if(Fav.is(tabdb.url)) {
    this.staricon.attr('src', Tab.starOn);
  } else {
    this.staricon.attr('src', Tab.starOff);
  }
  this.elem.append(this.staricon);

  this.staricon.hide();
  this.staricon.click(Tab.toggleFav).mousedown(consume).mouseup(consume);

  if(title) {
    rtabtitle = $('

').attr('class','title').text(title);
  } else {
    rtabtitle = $('

').attr('class','title').text(tabdb.title);
  }
  rtabtitle.css('padding-top', UI.TAB_TITLE_PADDING_TOP+'px');

  var tab = this;
  if(inPopup) {
    rtabtitle.mousedown(Tab.selectTab)
      .mouseup(consume).mousemove(consume);
  } else {
    this.elem.mousedown(function(ev) { tab.pick(ev); });
    $(document).mousemove(function(ev) { tab.drag(ev); });
    $(document).mouseup(function(ev) { tab.drop(ev); });
  }

  $('.node', this.elem).click(function(){
      tab.parent.toggleTree(tab);
      tab.setNodeIcon();
    }).mousedown(consume).mouseup(consume).mousemove(consume);
  $('.favicon', this.elem).click(Tab.selectTab)
    .mousedown(consume).mouseup(consume).mousemove(consume);

  this.elem.mouseenter(Tab.mouseenter);
  this.elem.mouseleave(Tab.mouseleave);

  this.elem.append(rtabtitle);

  this.elem.css({
    'margin-left' : (UI.DEPTH_STEP*tabdb.depth)+'px',
    'width' : (UI.winw-50-UI.DEPTH_STEP*tabdb.depth)+'px'
  });
  var wcorr = 30 + UI.scale * 10;
  $('div', this.elem).css({
    'width' : (UI.winw-140-wcorr-UI.DEPTH_STEP*tabdb.depth)+'px'
  });
    //$('.mtab', this.elem).css({'width': (UI.winw-50)+'px'})
    //$('.mtab > div', this.elem).css({'width': (UI.winw-140)+'px'})
}

Tab.fallbackIcon = chrome.extension.getURL('images/icon28.png');
Tab.starOn = chrome.extension.getURL('images/favon.png');
Tab.starOff = chrome.extension.getURL('images/favoff.png');
Tab.collapsedIcon = chrome.extension.getURL('images/collapsed.png');
Tab.expandedIcon = chrome.extension.getURL('images/expanded.png');
Tab.leafIcon = chrome.extension.getURL('images/leaf.png');

Tab.selectTab = function() {
  var match = /tab_(\d+)/.exec($(this).parent().attr('id'));
  if(match && match[1]) {
    chrome.tabs.update(parseInt(match[1]), {selected : true});
  }
  return false;
}

Tab.toggleFav = function() {
  var p = $(this).parent();
  var match = /tab_(\d+)/.exec(p.attr('id'));
  if(match && match[1]) {
    var tab = UI.tMap[parseInt(match[1])];
    if(Fav.is(tab.tabdb.url)) {
      Fav.remove(tab.tabdb.url);
      $(this).attr('src', Tab.starOff);
    } else {
      var fi = $(this).siblings('.favicon');
      Fav.add(tab.tabdb.url, fi.attr('src'));
      $(this).attr('src', Tab.starOn);
    }
    refresh_favorites();
  } else {
    alert('Error recognizing the tab');
  }
  return false;
}

Tab.mouseenter = function(ev) {
  $('.star', $(this)).show();
},

Tab.mouseleave = function(ev) {
  $('.star', $(this)).hide();
}

Tab.prototype = {
  setNodeIcon : function() {
    if(this.tabdb.isparent) {
      if(this.tabdb.collapsed) {
        this.nodeicon.attr('src', Tab.collapsedIcon);
      } else {
        this.nodeicon.attr('src', Tab.expandedIcon);
      }
    } else {
      this.nodeicon.attr('src', Tab.leafIcon);
    }
  },

  pick : function(ev) {
    var wframe = this.parent;
    this.carrier = wframe.removeTabSubtree(this);
    wframe.refreshStyle();
    UI.relayout_column(UI.get_column(ev.clientX));
    this.carrier.css({
      'position':'absolute',
      'top' : (ev.clientY-15)+'px',
      'left' : (ev.clientX - UI.winw/2)+'px',
      'width' : UI.winw+'px'
      });
    this.inTransit = true;
  },
  /*
  pick : function(ev) {
    this.reset_depth();

    this.detach(ev.clientY-15, ev.clientX - UI.winw/2);
    var wframe = this.parent;
    wframe.removeTab(this);
    wframe.refreshStyle();

    UI.relayout_column(UI.get_column(ev.clientX));
  },
  */

  detach : function(top, left) {
    this.elem.css({
      'position':'absolute',
      'top' : top+'px',
      'left' : left+'px',
      '-webkit-box-shadow' : 'rgba(20,20,20,1) 1px 1px 5px'
      });
    this.inTransit = true;
  },

  drag : function(ev) {
    if(this.inTransit) {
      //this.elem.css({
      this.carrier.css({
        'top' : (ev.clientY - 15)+'px',
        'left' : (ev.clientX - UI.winw/2)+'px'
      });
    }
  },

  attach : function() {
    this.inTransit = false;

    this.elem.css({
      'position':'relative',
      '-webkit-box-shadow' : null,
      'top': null,
      'left': null
    });
  },

  reset_depth : function() {
    this.elem.css({
      'margin-left' : '0px',
      'width' : (UI.winw-50)+'px'
    });
    var wcorr = 30 + UI.scale * 10;
    $('div', this.elem).css({
      'width' : (UI.winw-140-wcorr-UI.DEPTH_STEP*this.tabdb.depth)+'px'
    });
  },

  drop : function(ev) {
    if(!this.inTransit) return;

    // Check on which window are we dropping
    for(i in UI.wMap) {
      var win = UI.wMap[i];
      if(!win) continue; // for removed windows
      if(win.contains(ev.clientX, ev.clientY)) {

        //this.attach();
        //win.addTab(this);
        tidlist = win.addTabSubtree(this.carrier);

        win.refreshStyle();

        UI.relayout_column(UI.get_column(ev.clientX));

        bgport.postMessage({
          name : 'tabmove',
          tidlist : tidlist,
          wid : win.windb.wid
        });
        return;
      }
    }

    this.inTransit = false;
    this.elem.remove();

    bgport.postMessage({
      name : 'tabmovenew',
      tid : this.tabdb.tid,
    });
  },
}

<|endoftext|>


<commit_before>"use strict";

module.exports = function(notes) {
	var express = require('express');
	var url = require('url');
	var bodyParser = require('body-parser');
	var api = express.Router();

	api.use(bodyParser.json())

	api.use(function(req, res, next) {
		res.set('Content-Type', 'application/hal+json');
		res.set('Access-Control-Allow-Origin', '*');
		res.set('Access-Control-Allow-Credentials', 'true');
		res.set('Access-Control-Allow-Methods', '*');
		res.set('Access-Control-Allow-Headers', 'Content-Type, Accept');
		req.generateUrl = function(path) {
			var urlParts = url.parse(req.protocol + '://' + req.headers['host']);
			var port = parseInt(req.headers['x-forwarded-port'] ||  urlParts.port, 10);
			var protocol = req.headers['x-forwarded-proto'] || req.protocol;
			return protocol + '://' + req.hostname + ( port == 80 || port == 443 ? '' : ':' + port ) + req.baseUrl + path;
		};
		next();
	});

	api.get('/', function(req, res) {
		res.send(JSON.stringify({
			"_links": {
				"http://hateoas-notes/rels/notes": {"href": req.generateUrl('/notes')},
				"http://hateoas-notes/rels/create-note": {"href": req.generateUrl('/notes')}
			}
		}));
	});

	var noteToHal = function(req, note) {
		var halNote = note.toJSON();
		halNote["_links"] = {
			"self": {"href": req.generateUrl("/notes/" + note.getId())},
			"up": {"href": req.generateUrl("/notes")}
		};

		return halNote;
	};

	api.get('/notes', function(req, res) {
		var offset = parseInt(req.query.offset || 0, 10);
		var limit = parseInt(req.query.limit || 20, 10);

		notes.countNotes(function(err, totalCount) {
			notes.getNotesByOffsetAndLimit(offset, limit + 1, function(err, notes) {
				var halNotes = [];
				var hasNextPage = notes.length > limit ? true : false;
				notes.splice(limit, 1);

				notes.forEach(function(note) {
					halNotes.push(noteToHal(req, note));
				});

				var halResponse = {
					"_links": {
						"first": {"href": req.generateUrl('/notes?offset=0&limit=' + limit)},
						"self": {"href": req.generateUrl('/notes?offset=' + offset + '&limit=' + limit)},
						"up": {"href": req.generateUrl("/")},
						"last": {"href": req.generateUrl('/notes?offset=' + Math.floor(totalCount/limit) + '&limit=' + limit)}
					},
					"_embedded": {
						"http://hateoas-notes/rels/note": halNotes
					}
				};

				if (hasNextPage)
				{
					halResponse["_links"].next = {"href": req.generateUrl('/notes?offset=' + (limit + offset) + '&limit=' + limit)};
				}

				res.send(JSON.stringify(halResponse));
			});
		});
	});

	api.post('/notes', function(req, res) {
		notes.createNote(req.body, function(err, note) {
			res.statusCode = 201;
			res.setHeader('Location', req.generateUrl("/notes/" + note.getId()));
			res.end();
		});
	});

	api.get('/notes/:id', function(req, res) {
		notes.getNoteById(req.params.id, function(err, note) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.send(JSON.stringify(noteToHal(req, note)));
			}
		});
	});

	api.put('/notes/:id', function(req, res) {
		notes.updateNoteById(req.params.id, req.body, function(err, note) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.statusCode = 204;
				res.end();
			}
		});
	});

	api.delete('/notes/:id', function(req, res) {
		notes.deleteNoteById(req.params.id, function(err) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.statusCode = 204;
				res.end();
			}
		});
	});

	return api;
};<commit_msg>Hal: Add also links for `_embedded` notes (for easier navigation in HAL browser)<commit_after>"use strict";

module.exports = function(notes) {
	var express = require('express');
	var url = require('url');
	var bodyParser = require('body-parser');
	var api = express.Router();

	api.use(bodyParser.json())

	api.use(function(req, res, next) {
		res.set('Content-Type', 'application/hal+json');
		res.set('Access-Control-Allow-Origin', '*');
		res.set('Access-Control-Allow-Credentials', 'true');
		res.set('Access-Control-Allow-Methods', '*');
		res.set('Access-Control-Allow-Headers', 'Content-Type, Accept');
		req.generateUrl = function(path) {
			var urlParts = url.parse(req.protocol + '://' + req.headers['host']);
			var port = parseInt(req.headers['x-forwarded-port'] ||  urlParts.port, 10);
			var protocol = req.headers['x-forwarded-proto'] || req.protocol;
			return protocol + '://' + req.hostname + ( port == 80 || port == 443 ? '' : ':' + port ) + req.baseUrl + path;
		};
		next();
	});

	api.get('/', function(req, res) {
		res.send(JSON.stringify({
			"_links": {
				"http://hateoas-notes/rels/notes": {"href": req.generateUrl('/notes')},
				"http://hateoas-notes/rels/create-note": {"href": req.generateUrl('/notes')}
			}
		}));
	});

	var noteToHal = function(req, note) {
		var halNote = note.toJSON();
		halNote["_links"] = {
			"self": {"href": req.generateUrl("/notes/" + note.getId())},
			"up": {"href": req.generateUrl("/notes")}
		};

		return halNote;
	};

	api.get('/notes', function(req, res) {
		var offset = parseInt(req.query.offset || 0, 10);
		var limit = parseInt(req.query.limit || 20, 10);

		notes.countNotes(function(err, totalCount) {
			notes.getNotesByOffsetAndLimit(offset, limit + 1, function(err, notes) {
				var halNotes = [];
				var hasNextPage = notes.length > limit ? true : false;
				notes.splice(limit, 1);

				var halResponse = {
					"_links": {
						"first": {"href": req.generateUrl('/notes?offset=0&limit=' + limit)},
						"self": {"href": req.generateUrl('/notes?offset=' + offset + '&limit=' + limit)},
						"up": {"href": req.generateUrl("/")},
						"last": {"href": req.generateUrl('/notes?offset=' + Math.floor(totalCount/limit) + '&limit=' + limit)},
						"http://hateoas-notes/rels/note": []
					},
					"_embedded": {
						"http://hateoas-notes/rels/note": []
					}
				};

				notes.forEach(function(note) {
					halResponse["_embedded"]["http://hateoas-notes/rels/note"].push(noteToHal(req, note));
					halResponse["_links"]["http://hateoas-notes/rels/note"].push({"href": req.generateUrl("/notes/" + note.getId())});
				});

				if (hasNextPage)
				{
					halResponse["_links"].next = {"href": req.generateUrl('/notes?offset=' + (limit + offset) + '&limit=' + limit)};
				}

				res.send(JSON.stringify(halResponse));
			});
		});
	});

	api.post('/notes', function(req, res) {
		notes.createNote(req.body, function(err, note) {
			res.statusCode = 201;
			res.setHeader('Location', req.generateUrl("/notes/" + note.getId()));
			res.end();
		});
	});

	api.get('/notes/:id', function(req, res) {
		notes.getNoteById(req.params.id, function(err, note) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.send(JSON.stringify(noteToHal(req, note)));
			}
		});
	});

	api.put('/notes/:id', function(req, res) {
		notes.updateNoteById(req.params.id, req.body, function(err, note) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.statusCode = 204;
				res.end();
			}
		});
	});

	api.delete('/notes/:id', function(req, res) {
		notes.deleteNoteById(req.params.id, function(err) {
			if (err)
			{
				res.statusCode = 404;
				res.send(JSON.stringify({
					"message": "Note with id: " + req.params.id + " not found!"
				}));
			}
			else
			{
				res.statusCode = 204;
				res.end();
			}
		});
	});

	return api;
};<|endoftext|>


<commit_before>// Filename: scrounge_adapt.js
// Timestamp: 2018.04.07-19:01:44 (last modified)
// Author(s): bumblehead <chris@bumblehead.com>

const umd = require('umd'),
      path = require('path'),
      less = require('less'),
      babel = require('babel-core'),
      babelpresetenv = require('babel-preset-env'),
      umdname = require('umdname'),
      Cleancss = require('clean-css'),
      moduletype = require('moduletype'),
      typescript = require('typescript'),
      replacerequires = require('replace-requires'),
      replaceimports = require('replace-imports'),

      scrounge_uid = require('./scrounge_uid');

module.exports = (o => {
  o = (opts, node, fn) => {
    let filepath = node.get('filepath'),
        extname = path.extname(filepath).slice(1),
        str = node.get('content');

    opts.embedarr.map(embed => {
      if (~filepath.indexOf(embed.filepath)) {
        str = embed.content + str;
      }
    });

    opts.globalarr.map(global => {
      // module namespace defined on user-given name
      if (~filepath.indexOf(global.filepath)) {
        str += '\nif (typeof window === "object") window.:NAME = :UID;'
          .replace(/:NAME/g, global.name)
          .replace(/:UID/g, scrounge_uid.sanitised(node.get('uid')));
      }
    });

    if (extname && typeof o[extname] === 'function') {
      o[extname](opts, node, str, fn);
    } else {
      fn(null, str);
    }
  };

  o.try = (path, fn) => {
    try {
      return fn();
    } catch (e) {
      console.error(e);

      throw new Error(`[!!!] parse error ${path}`);
    }
  };

  o.js = (opts, node, str, fn) => {
    let filepath = node.get('filepath'),
        modname = scrounge_uid.sanitised(node.get('uid')),
        skip = opts.skippatharr
          .some(path => ~filepath.indexOf(path));

    if (skip)
      return fn(null, str);

    str = o.try(filepath, () => (
      babel.transform(str, {
        compact : opts.iscompress && !skip,
        presets : opts.ises2015 ? [
          babelpresetenv
        ] : [],
        plugins : opts.babelpluginarr || []
      })).code);

    if (moduletype.umd(str)) {
      str = umdname(str, modname);
    } else if (moduletype.cjs(str) ||
               moduletype.esm(str)) {
      if (moduletype.cjs(str) && !moduletype.esm(str)) {
        str = umd(modname, str, { commonJS : true });
      }

      // build import and require replacement mappings
      let replace = node.get('outarr').reduce((prev, cur) => {
        let refname = cur.get('refname'),
            depname = scrounge_uid.sanitised(cur.get('uid'));

        opts.aliasarr.map(([ matchname, newname ]) => (
          newname === refname &&
            (prev[matchname] = depname)
        ));

        prev.require[refname] = depname;
        prev.import[refname] = `./${depname}.js`;

        return prev;
      }, {
        require : {},
        import : {}
      });

      str = replacerequires(str, replace.require);
      str = replaceimports(str, replace.import);
    }

    fn(null, str);
  };

  // perform o.js on mjs files
  o.mjs = o.js;

  o.ts = (opts, node, str, fn) => {
    let tsconfig = opts.tsconfig || {},
        jsstr = typescript.transpileModule(str, tsconfig).outputText;

    o.js(opts, node, jsstr, fn);
  };

  // perform o.ts on tsx files
  o.tsx = o.ts;

  o.css = (opts, node, str, fn) => {
    fn(null, opts.iscompress ?
      new Cleancss().minify(str).styles : str);
  };

  o.less = (opts, node, str, fn) => {
    less.render(str, {
      filename : path.resolve(node.get('filepath'))
    }, (err, output) => {
      if (err) console.error(err);

      return err ? fn(err) : o.css(opts, node, output.css, fn);
    });
  };

  return o;
})({});
<commit_msg>do not replace require, import unless iscjs, isesm<commit_after>// Filename: scrounge_adapt.js
// Timestamp: 2018.04.08-03:46:11 (last modified)
// Author(s): bumblehead <chris@bumblehead.com>

const umd = require('umd'),
      path = require('path'),
      less = require('less'),
      babel = require('babel-core'),
      babelpresetenv = require('babel-preset-env'),
      umdname = require('umdname'),
      Cleancss = require('clean-css'),
      moduletype = require('moduletype'),
      typescript = require('typescript'),
      replacerequires = require('replace-requires'),
      replaceimports = require('replace-imports'),

      scrounge_uid = require('./scrounge_uid');

module.exports = (o => {
  o = (opts, node, fn) => {
    let filepath = node.get('filepath'),
        extname = path.extname(filepath).slice(1),
        str = node.get('content');

    opts.embedarr.map(embed => {
      if (~filepath.indexOf(embed.filepath)) {
        str = embed.content + str;
      }
    });

    opts.globalarr.map(global => {
      // module namespace defined on user-given name
      if (~filepath.indexOf(global.filepath)) {
        str += '\nif (typeof window === "object") window.:NAME = :UID;'
          .replace(/:NAME/g, global.name)
          .replace(/:UID/g, scrounge_uid.sanitised(node.get('uid')));
      }
    });

    if (extname && typeof o[extname] === 'function') {
      o[extname](opts, node, str, fn);
    } else {
      fn(null, str);
    }
  };

  o.try = (path, fn) => {
    try {
      return fn();
    } catch (e) {
      console.error(e);

      throw new Error(`[!!!] parse error ${path}`);
    }
  };

  o.js = (opts, node, str, fn) => {
    let filepath = node.get('filepath'),
        modname = scrounge_uid.sanitised(node.get('uid')),
        skip = opts.skippatharr.some(path => ~filepath.indexOf(path)),
        iscjs,
        isesm;

    if (skip)
      return fn(null, str);

    str = o.try(filepath, () => (
      babel.transform(str, {
        compact : opts.iscompress && !skip,
        presets : opts.ises2015 ? [
          babelpresetenv
        ] : [],
        plugins : opts.babelpluginarr || []
      })).code);

    iscjs = moduletype.cjs(str);
    isesm = moduletype.esm(str);

    if (moduletype.umd(str)) {
      str = umdname(str, modname);
    } else if (iscjs || isesm) {
      if (iscjs && !isesm)
        str = umd(modname, str, { commonJS : true });

      // build import and require replacement mappings
      let replace = node.get('outarr').reduce((prev, cur) => {
        let refname = cur.get('refname'),
            depname = scrounge_uid.sanitised(cur.get('uid'));

        opts.aliasarr.map(([ matchname, newname ]) => (
          newname === refname &&
            (prev[matchname] = depname)
        ));

        prev.require[refname] = depname;
        prev.import[refname] = `./${depname}.js`;

        return prev;
      }, {
        require : {},
        import : {}
      });

      if (iscjs)
        str = replacerequires(str, replace.require);

      if (isesm)
        str = replaceimports(str, replace.import);
    }

    fn(null, str);
  };

  // perform o.js on mjs files
  o.mjs = o.js;

  o.ts = (opts, node, str, fn) => {
    let tsconfig = opts.tsconfig || {},
        jsstr = typescript.transpileModule(str, tsconfig).outputText;

    o.js(opts, node, jsstr, fn);
  };

  // perform o.ts on tsx files
  o.tsx = o.ts;

  o.css = (opts, node, str, fn) => {
    fn(null, opts.iscompress ?
      new Cleancss().minify(str).styles : str);
  };

  o.less = (opts, node, str, fn) => {
    less.render(str, {
      filename : path.resolve(node.get('filepath'))
    }, (err, output) => {
      if (err) console.error(err);

      return err ? fn(err) : o.css(opts, node, output.css, fn);
    });
  };

  return o;
})({});
<|endoftext|>