<commit_before>// The API references it's viewer.
DV.Api = function(viewer) {
  this.viewer = viewer;
};

// Set up the API class.
DV.Api.prototype = {

  // Return the current page of the document.
  currentPage : function() {
    return this.viewer.models.document.currentPage();
  },

  // Set the current page of the document.
  setCurrentPage : function(page) {
    this.viewer.helpers.jump(page - 1);
  },

  // Register a callback for when the page is changed.
  onPageChange : function(callback) {
    this.viewer.models.document.onPageChangeCallbacks.push(callback);
  },

  // Return the page number for one of the three physical page DOM elements, by id:
  getPageNumberForId : function(id) {
    var page = this.viewer.pageSet.pages[id];
    return page.index + 1;
  },

  // Get the document's canonical schema
  getSchema : function() {
    return this.viewer.schema.document;
  },

  // Get the document's canonical ID.
  getId : function() {
    return this.viewer.schema.document.id;
  },

  // Get the document's numerical ID.
  getModelId : function() {
    return parseInt(this.getId(), 10);
  },

  // Return the current zoom factor of the document.
  currentZoom : function() {
    var doc = this.viewer.models.document;
    return doc.zoomLevel / doc.ZOOM_RANGES[1];
  },

  // Return the current zoom factor of the document relative to the base zoom.
  relativeZoom : function() {
    var models = this.viewer.models;
    var zoom   = this.currentZoom();
    return zoom * (models.document.ZOOM_RANGES[1] / models.pages.BASE_WIDTH);
  },

  // Return the total number of pages in the document.
  numberOfPages : function() {
    return this.viewer.models.document.totalPages;
  },

  // Return the name of the conributor, if available.
  getContributor : function() {
    return this.viewer.schema.document.contributor;
  },

  // Return the name of the contributing organization, if available.
  getContributorOrganization : function() {
    return this.viewer.schema.document.contributor_organization;
  },

  // Change the documents' sections, re-rendering the navigation. "sections"
  // should be an array of sections in the canonical format:
  // {title: "Chapter 1", pages: "1-12"}
  setSections : function(sections) {
    sections = _.sortBy(sections, function(s){ return s.page; });
    this.viewer.schema.data.sections = sections;
    this.viewer.models.chapters.loadChapters();
    this.redraw();
  },

  // Get a list of every section in the document.
  getSections : function() {
    return _.clone(this.viewer.schema.data.sections || []);
  },

  // Get the document's description.
  getDescription : function() {
    return this.viewer.schema.document.description;
  },

  // Set the document's description and update the sidebar.
  setDescription : function(desc) {
    this.viewer.schema.document.description = desc;
    this.viewer.$('.DV-description').remove();
    this.viewer.$('.DV-navigation').prepend(JST.descriptionContainer({description: desc}));
    this.viewer.helpers.displayNavigation();
  },

  // Get the document's related article url.
  getRelatedArticle : function() {
    return this.viewer.schema.document.resources.related_article;
  },

  // Set the document's related article url.
  setRelatedArticle : function(url) {
    this.viewer.schema.document.resources.related_article = url;
    this.viewer.$('.DV-storyLink a').attr({href : url});
    this.viewer.$('.DV-storyLink').toggle(!!url);
  },

  // Get the document's published url.
  getPublishedUrl : function() {
    return this.viewer.schema.document.resources.published_url;
  },

  // Set the document's published url.
  setPublishedUrl : function(url) {
    this.viewer.schema.document.resources.published_url = url;
  },

  // Get the document's title.
  getTitle : function() {
    return this.viewer.schema.document.title;
  },

  // Set the document's title.
  setTitle : function(title) {
    this.viewer.schema.document.title = title;
    document.title = title;
  },

  getSource : function() {
    return this.viewer.schema.document.source;
  },

  setSource : function(source) {
    this.viewer.schema.document.source = source;
  },

  getPageText : function(pageNumber) {
    return this.viewer.schema.text[pageNumber - 1];
  },

  // Set the page text for the given page of a document in the local cache.
  setPageText : function(text, pageNumber) {
    this.viewer.schema.text[pageNumber - 1] = text;
  },

  // Reset all modified page text to the original values from the server cache.
  resetPageText : function(overwriteOriginal) {
    var self = this;
    var pageText = this.viewer.schema.text;
    if (overwriteOriginal) {
      this.viewer.models.document.originalPageText = {};
    } else {
      _.each(this.viewer.models.document.originalPageText, function(originalPageText, pageNumber) {
        pageNumber = parseInt(pageNumber, 10);
        if (originalPageText != pageText[pageNumber-1]) {
          self.setPageText(originalPageText, pageNumber);
          if (pageNumber == self.currentPage()) {
            self.viewer.events.loadText();
          }
        }
      });
    }
    if (this.viewer.openEditor == 'editText') {
      this.viewer.$('.DV-textContents').attr('contentEditable', true).addClass('DV-editing');
    }
  },

  // Redraw the UI. Call redraw(true) to also redraw annotations and pages.
  redraw : function(redrawAll) {
    if (redrawAll) {
      this.viewer.models.annotations.renderAnnotations();
      this.viewer.models.document.computeOffsets();
    }
    this.viewer.helpers.renderNavigation();
    this.viewer.helpers.renderComponents();
    if (redrawAll) {
      this.viewer.elements.window.removeClass('DV-coverVisible');
      this.viewer.pageSet.buildPages({noNotes : true});
      this.viewer.pageSet.reflowPages();
    }
  },

  // Add a new annotation to the document, prefilled to any extent.
  addAnnotation : function(anno) {
    anno = this.viewer.schema.loadAnnotation(anno);
    this.viewer.models.annotations.sortAnnotations();
    this.redraw(true);
    this.viewer.pageSet.showAnnotation(anno, {active: true, edit : true});
    return anno;
  },

  // Register a callback for when an annotation is saved.
  onAnnotationSave : function(callback) {
    this.viewer.models.annotations.saveCallbacks.push(callback);
  },

  // Register a callback for when an annotation is deleted.
  onAnnotationDelete : function(callback) {
    this.viewer.models.annotations.deleteCallbacks.push(callback);
  },

  setConfirmStateChange : function(callback) {
    this.viewer.confirmStateChange = callback;
  },

  onChangeState : function(callback) {
    this.viewer.onStateChangeCallbacks.push(callback);
  },

  resetRemovedPages : function() {
    this.viewer.models.document.resetRemovedPages();
  },

  addPageToRemovedPages : function(page) {
    this.viewer.models.document.addPageToRemovedPages(page);
  },

  removePageFromRemovedPages : function(page) {
    this.viewer.models.document.removePageFromRemovedPages(page);
  },

  resetReorderedPages : function() {
    this.viewer.models.document.redrawReorderedPages();
  },

  reorderPages : function(pageOrder, options) {
    var model = this.getModelId();
    this.viewer.models.document.reorderPages(model, pageOrder, options);
  },

  // Request the loading of an external JS file.
  loadJS : function(url, callback) {
    DV.jQuery.getScript(url, callback);
  },

  // Set first/last styles for tabs.
  roundTabCorners : function() {
    var tabs = this.viewer.$('.DV-views > div:visible');
    tabs.first().addClass('DV-first');
    tabs.last().addClass('DV-last');
  },

  // ---------------------- Enter/Leave Edit Modes -----------------------------

  enterRemovePagesMode : function() {
    this.viewer.openEditor = 'removePages';
  },

  leaveRemovePagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterAddPagesMode : function() {
    this.viewer.openEditor = 'addPages';
  },

  leaveAddPagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterReplacePagesMode : function() {
    this.viewer.openEditor = 'replacePages';
  },

  leaveReplacePagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterReorderPagesMode : function() {
    this.viewer.openEditor = 'reorderPages';
    this.viewer.elements.viewer.addClass('DV-reorderPages');
  },

  leaveReorderPagesMode : function() {
    this.resetReorderedPages();
    this.viewer.openEditor = null;
    this.viewer.elements.viewer.removeClass('DV-reorderPages');
  },

  enterEditPageTextMode : function() {
    this.viewer.openEditor = 'editText';
    this.viewer.events.loadText();
  },

  leaveEditPageTextMode : function() {
    this.viewer.openEditor = null;
    this.resetPageText();
  }

};
<commit_msg>add getState as a shortcut to currentDocument.models.document.viewer.state<commit_after>// The API references it's viewer.
DV.Api = function(viewer) {
  this.viewer = viewer;
};

// Set up the API class.
DV.Api.prototype = {

  // Return the current page of the document.
  currentPage : function() {
    return this.viewer.models.document.currentPage();
  },

  // Set the current page of the document.
  setCurrentPage : function(page) {
    this.viewer.helpers.jump(page - 1);
  },

  // Register a callback for when the page is changed.
  onPageChange : function(callback) {
    this.viewer.models.document.onPageChangeCallbacks.push(callback);
  },

  // Return the page number for one of the three physical page DOM elements, by id:
  getPageNumberForId : function(id) {
    var page = this.viewer.pageSet.pages[id];
    return page.index + 1;
  },

  // Get the document's canonical schema
  getSchema : function() {
    return this.viewer.schema.document;
  },

  // Get the document's canonical ID.
  getId : function() {
    return this.viewer.schema.document.id;
  },

  // Get the document's numerical ID.
  getModelId : function() {
    return parseInt(this.getId(), 10);
  },

  // Return the current zoom factor of the document.
  currentZoom : function() {
    var doc = this.viewer.models.document;
    return doc.zoomLevel / doc.ZOOM_RANGES[1];
  },

  // Return the current zoom factor of the document relative to the base zoom.
  relativeZoom : function() {
    var models = this.viewer.models;
    var zoom   = this.currentZoom();
    return zoom * (models.document.ZOOM_RANGES[1] / models.pages.BASE_WIDTH);
  },

  // Return the total number of pages in the document.
  numberOfPages : function() {
    return this.viewer.models.document.totalPages;
  },

  // Return the name of the conributor, if available.
  getContributor : function() {
    return this.viewer.schema.document.contributor;
  },

  // Return the name of the contributing organization, if available.
  getContributorOrganization : function() {
    return this.viewer.schema.document.contributor_organization;
  },

  // Change the documents' sections, re-rendering the navigation. "sections"
  // should be an array of sections in the canonical format:
  // {title: "Chapter 1", pages: "1-12"}
  setSections : function(sections) {
    sections = _.sortBy(sections, function(s){ return s.page; });
    this.viewer.schema.data.sections = sections;
    this.viewer.models.chapters.loadChapters();
    this.redraw();
  },

  // Get a list of every section in the document.
  getSections : function() {
    return _.clone(this.viewer.schema.data.sections || []);
  },

  // Get the document's description.
  getDescription : function() {
    return this.viewer.schema.document.description;
  },

  // Set the document's description and update the sidebar.
  setDescription : function(desc) {
    this.viewer.schema.document.description = desc;
    this.viewer.$('.DV-description').remove();
    this.viewer.$('.DV-navigation').prepend(JST.descriptionContainer({description: desc}));
    this.viewer.helpers.displayNavigation();
  },

  // Get the document's related article url.
  getRelatedArticle : function() {
    return this.viewer.schema.document.resources.related_article;
  },

  // Set the document's related article url.
  setRelatedArticle : function(url) {
    this.viewer.schema.document.resources.related_article = url;
    this.viewer.$('.DV-storyLink a').attr({href : url});
    this.viewer.$('.DV-storyLink').toggle(!!url);
  },

  // Get the document's published url.
  getPublishedUrl : function() {
    return this.viewer.schema.document.resources.published_url;
  },

  // Set the document's published url.
  setPublishedUrl : function(url) {
    this.viewer.schema.document.resources.published_url = url;
  },

  // Get the document's title.
  getTitle : function() {
    return this.viewer.schema.document.title;
  },

  // Set the document's title.
  setTitle : function(title) {
    this.viewer.schema.document.title = title;
    document.title = title;
  },

  getSource : function() {
    return this.viewer.schema.document.source;
  },

  setSource : function(source) {
    this.viewer.schema.document.source = source;
  },

  getPageText : function(pageNumber) {
    return this.viewer.schema.text[pageNumber - 1];
  },

  // Set the page text for the given page of a document in the local cache.
  setPageText : function(text, pageNumber) {
    this.viewer.schema.text[pageNumber - 1] = text;
  },

  // Reset all modified page text to the original values from the server cache.
  resetPageText : function(overwriteOriginal) {
    var self = this;
    var pageText = this.viewer.schema.text;
    if (overwriteOriginal) {
      this.viewer.models.document.originalPageText = {};
    } else {
      _.each(this.viewer.models.document.originalPageText, function(originalPageText, pageNumber) {
        pageNumber = parseInt(pageNumber, 10);
        if (originalPageText != pageText[pageNumber-1]) {
          self.setPageText(originalPageText, pageNumber);
          if (pageNumber == self.currentPage()) {
            self.viewer.events.loadText();
          }
        }
      });
    }
    if (this.viewer.openEditor == 'editText') {
      this.viewer.$('.DV-textContents').attr('contentEditable', true).addClass('DV-editing');
    }
  },

  // Redraw the UI. Call redraw(true) to also redraw annotations and pages.
  redraw : function(redrawAll) {
    if (redrawAll) {
      this.viewer.models.annotations.renderAnnotations();
      this.viewer.models.document.computeOffsets();
    }
    this.viewer.helpers.renderNavigation();
    this.viewer.helpers.renderComponents();
    if (redrawAll) {
      this.viewer.elements.window.removeClass('DV-coverVisible');
      this.viewer.pageSet.buildPages({noNotes : true});
      this.viewer.pageSet.reflowPages();
    }
  },

  // Add a new annotation to the document, prefilled to any extent.
  addAnnotation : function(anno) {
    anno = this.viewer.schema.loadAnnotation(anno);
    this.viewer.models.annotations.sortAnnotations();
    this.redraw(true);
    this.viewer.pageSet.showAnnotation(anno, {active: true, edit : true});
    return anno;
  },

  // Register a callback for when an annotation is saved.
  onAnnotationSave : function(callback) {
    this.viewer.models.annotations.saveCallbacks.push(callback);
  },

  // Register a callback for when an annotation is deleted.
  onAnnotationDelete : function(callback) {
    this.viewer.models.annotations.deleteCallbacks.push(callback);
  },

  setConfirmStateChange : function(callback) {
    this.viewer.confirmStateChange = callback;
  },

  onChangeState : function(callback) {
    this.viewer.onStateChangeCallbacks.push(callback);
  },

  getState : function() {
    return this.viewer.state;
  },

  resetRemovedPages : function() {
    this.viewer.models.document.resetRemovedPages();
  },

  addPageToRemovedPages : function(page) {
    this.viewer.models.document.addPageToRemovedPages(page);
  },

  removePageFromRemovedPages : function(page) {
    this.viewer.models.document.removePageFromRemovedPages(page);
  },

  resetReorderedPages : function() {
    this.viewer.models.document.redrawReorderedPages();
  },

  reorderPages : function(pageOrder, options) {
    var model = this.getModelId();
    this.viewer.models.document.reorderPages(model, pageOrder, options);
  },

  // Request the loading of an external JS file.
  loadJS : function(url, callback) {
    DV.jQuery.getScript(url, callback);
  },

  // Set first/last styles for tabs.
  roundTabCorners : function() {
    var tabs = this.viewer.$('.DV-views > div:visible');
    tabs.first().addClass('DV-first');
    tabs.last().addClass('DV-last');
  },

  // ---------------------- Enter/Leave Edit Modes -----------------------------

  enterRemovePagesMode : function() {
    this.viewer.openEditor = 'removePages';
  },

  leaveRemovePagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterAddPagesMode : function() {
    this.viewer.openEditor = 'addPages';
  },

  leaveAddPagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterReplacePagesMode : function() {
    this.viewer.openEditor = 'replacePages';
  },

  leaveReplacePagesMode : function() {
    this.viewer.openEditor = null;
  },

  enterReorderPagesMode : function() {
    this.viewer.openEditor = 'reorderPages';
    this.viewer.elements.viewer.addClass('DV-reorderPages');
  },

  leaveReorderPagesMode : function() {
    this.resetReorderedPages();
    this.viewer.openEditor = null;
    this.viewer.elements.viewer.removeClass('DV-reorderPages');
  },

  enterEditPageTextMode : function() {
    this.viewer.openEditor = 'editText';
    this.viewer.events.loadText();
  },

  leaveEditPageTextMode : function() {
    this.viewer.openEditor = null;
    this.resetPageText();
  }

};
<|endoftext|>


<commit_before>if (typeof define !== 'function') { var define = require('amdefine')(module); }
define([
	'jquery',
	'app/Player',
	'app/Point',
	'app/Line'
], function(
	$,
	Player,
	Point,
	Line
) {
	return function() {
		//canvas
		var width = 800, height = 600;
		var canvas = $('<canvas width="' + width + 'px" height = "' + height + 'px" />').appendTo(document.body);
		var ctx = canvas[0].getContext('2d');

		//create stuff
		var player = new Player(1000, 1000);
		var camera = { x: player.pos.x, y: player.pos.y };
		var obstacles = [];
		var grapples = [];
		function createPoly(points, reverse) {
			var i, line, point, lines = [];
			if(reverse) {
				var reversedPoints = [];
				for(i = 0; i < points.length; i += 2) {
					reversedPoints[i] = points[points.length - i - 2];
					reversedPoints[i+1] = points[points.length - i - 1];
				}
				points = reversedPoints;
			}
			//create the lines
			for(i = 0; i < points.length - 2; i += 2) {
				line = new Line(points[i], points[i + 1], points[i + 2], points[i + 3]);
				lines.push(line);
				obstacles.push(line);
			}
			line = new Line(points[points.length - 2], points[points.length - 1], points[0], points[1]);
			lines.push(line);
			obstacles.push(line);
			//create the points
			for(i = 0; i < lines.length - 1; i++) {
				point = new Point(lines[i].end.x, lines[i].end.y);
				point.addParent(lines[i]);
				point.addParent(lines[i + 1]);
				obstacles.push(point);
			}
			point = new Point(lines[0].start.x, lines[0].start.y);
			point.addParent(lines[0]);
			point.addParent(lines[lines.length - 1]);
			obstacles.push(point);
		}
		createPoly([900,1100,  1100,1100, 1100,1110,  900,1110],  true);
		createPoly([600,1210,  600,1220,  710,1220,   710,1210]);
		createPoly([1300,900,  1400,1000, 1300,1000], true);
		createPoly([1500,900,  1510,900,  1510,600,   1500,600]);
		createPoly([1600,860,  1590,860,  1590,600,   1600,600], true);
		createPoly([980,1220,  900,1180,  900,1170,   1100,1170, 1100,1180, 1020,1220], true);
		createPoly([200,1510,  200,1500,  2000,1500,  2000,1510],  true);
		createPoly([1300,1315, 1260,1250, 1300,1340,  1340,1250]);
		createPoly([1400,1300, 1360,1250, 1400,1320,  1440,1250]);
		createPoly([1500,1285, 1460,1250, 1500,1320,  1540,1250]);
		createPoly([1600,1270, 1560,1250, 1600,1320,  1640,1250]);
		createPoly([1600,1100, 1560,1150, 1600,1080,  1640,1150], true);

		//add input bindings
		var keys = { pressed: {} };
		var KEY = { W: 87, A: 65, S: 83, D: 68, R: 82, G: 71, SHIFT: 16, SPACE: 32 };
		var JUMP_KEY = KEY.SPACE;
		$(document).on('keydown', function(evt) {
			if(!keys[evt.which]) {
				keys[evt.which] = true;
				keys.pressed[evt.which] = true;
			}
		});
		$(document).on('keyup', function(evt) {
			if(keys[evt.which]) {
				keys[evt.which] = false;
				keys.pressed[evt.which] = false;
			}
		});
		$(document).on('mousedown', function(evt) {
			grapples.push(player.shootGrapple(evt.clientX + camera.x, evt.clientY + camera.y));
		});

		function everyFrame(ms) {
			tick(ms);
			camera.x = player.pos.x - width / 2;
			camera.y = player.pos.y - height / 2;
			render();
		}

		var interruptionsLastFrame = [];
		function tick(ms) {
			var i, j, interruption, friction = 1;
			for(i = 0; i < grapples.length; i++) {
				if(!grapples[i].isDead && !grapples[i].isLatched) {
					var earliestGrappleCollision = null;
					grapples[i].tick(ms, friction);
					for(j = 0; j < obstacles.length; j++) {
						var collision = obstacles[j].checkForCollisionWithMovingPoint(grapples[i]);
						if(collision && (!earliestGrappleCollision || earliestGrappleCollision.distPreContact > collision.distPreContact)) {
							earliestGrappleCollision = collision;
						}
					}
					if(earliestGrappleCollision) {
						grapples[i].latchTo(earliestGrappleCollision.posOnContact.x, earliestGrappleCollision.posOnContact.y);
					}
				}
			}
			player.applyForce(0, 600); //gravity
			if(keys[KEY.A]) { player.applyForce(-400, 0); }
			if(keys[KEY.D]) { player.applyForce(400, 0); }
			if(keys[KEY.W]) { player.applyForce(0, -400); }
			if(keys[KEY.S]) { player.applyForce(0, 400); }
			if(keys.pressed[JUMP_KEY]) {
				for(i = 0; i < interruptionsLastFrame.length; i++) {
					interruption = interruptionsLastFrame[i];
					if(interruption.interruptionType === 'collision') {
						keys.pressed[JUMP_KEY] = false;
						player.jump(interruption.jumpDir.x, interruption.jumpDir.y);
						break;
					}
				}
			}
			player.tick(ms, friction);
			var interruptionsThisFrame = [];
			interruption = null;
			for(i = 0; i <= 6; i++) {
				if(i === 6) {
					interruption = {
						interruptionType: 'limit',
						posOnContact: { x: player.pos.prev.x, y: player.pos.prev.y },
						posAfterContact: { x: player.pos.prev.x, y: player.pos.prev.y },
						velAfterContact: { x: 0, y: 0 }
					};
				}
				else {
					interruption = findInterruption(interruptionsThisFrame);
				}
				if(interruption) {
					interruptionsThisFrame.push(interruption);
					player.pos.x = interruption.posAfterContact.x;
					player.pos.y = interruption.posAfterContact.y;
					player.pos.prev.x = interruption.posOnContact.x;
					player.pos.prev.y = interruption.posOnContact.y;
					player.vel.x = interruption.velAfterContact.x;
					player.vel.y = interruption.velAfterContact.y;
				}
				else {
					break;
				}
			}
			if(interruptionsThisFrame.length > 1) {
				console.log(interruptionsThisFrame.length + " interruptions");
			}
			interruptionsLastFrame = interruptionsThisFrame;
		}

		function findInterruption(prevInterruptions) {
			var i, j, earliestInterruption = null;
			var prevInterruption = (prevInterruptions.length > 0 ? prevInterruptions[prevInterruptions.length - 1] : null);
			for(i = 0; i < obstacles.length; i++) {
				var collision = obstacles[i].checkForCollisionWithMovingCircle(player);
				if(collision && (!earliestInterruption || earliestInterruption.distPreContact > collision.distPreContact) &&
					(!prevInterruption || prevInterruption.interruptionType !== 'collision' || !prevInterruption.obstacle.sameAs(collision.obstacle))) {
					collision.interruptionType = 'collision';
					earliestInterruption = collision;
				}
			}
			for(i = 0; i < grapples.length; i++) {
				var violation = grapples[i].checkForMaxTether();
				if(violation && (!earliestInterruption || earliestInterruption.distPreContact > violation.distPreContact) &&
					(!prevInterruption || prevInterruption.interruptionType !== 'grapple' || !prevInterruption.grapple.sameAs(violation.grapple))) {
					violation.interruptionType = 'grapple';
					earliestInterruption = violation;
				}
			}
			return earliestInterruption;
		}

		function render() {
			var i;
			ctx.fillStyle = '#fff';
			ctx.fillRect(0, 0, width, height);
			for(i = 0; i < grapples.length; i++) {
				grapples[i].render(ctx, camera);
			}
			player.render(ctx, camera);
			for(i = 0; i < obstacles.length; i++) {
				obstacles[i].render(ctx, camera);
			}
		}

		//set up animation frame functionality
		var prevTime;
		requestAnimationFrame(function(time) {
			prevTime = time;
			loop(time);
		});
		function loop(time) {
			var ms = time - prevTime;
			prevTime = time;
			everyFrame(ms, time);
			requestAnimationFrame(loop);
		}
	};
});<commit_msg>Got rid of console.log<commit_after>if (typeof define !== 'function') { var define = require('amdefine')(module); }
define([
	'jquery',
	'app/Player',
	'app/Point',
	'app/Line'
], function(
	$,
	Player,
	Point,
	Line
) {
	return function() {
		//canvas
		var width = 800, height = 600;
		var canvas = $('<canvas width="' + width + 'px" height = "' + height + 'px" />').appendTo(document.body);
		var ctx = canvas[0].getContext('2d');

		//create stuff
		var player = new Player(1000, 1000);
		var camera = { x: player.pos.x, y: player.pos.y };
		var obstacles = [];
		var grapples = [];
		function createPoly(points, reverse) {
			var i, line, point, lines = [];
			if(reverse) {
				var reversedPoints = [];
				for(i = 0; i < points.length; i += 2) {
					reversedPoints[i] = points[points.length - i - 2];
					reversedPoints[i+1] = points[points.length - i - 1];
				}
				points = reversedPoints;
			}
			//create the lines
			for(i = 0; i < points.length - 2; i += 2) {
				line = new Line(points[i], points[i + 1], points[i + 2], points[i + 3]);
				lines.push(line);
				obstacles.push(line);
			}
			line = new Line(points[points.length - 2], points[points.length - 1], points[0], points[1]);
			lines.push(line);
			obstacles.push(line);
			//create the points
			for(i = 0; i < lines.length - 1; i++) {
				point = new Point(lines[i].end.x, lines[i].end.y);
				point.addParent(lines[i]);
				point.addParent(lines[i + 1]);
				obstacles.push(point);
			}
			point = new Point(lines[0].start.x, lines[0].start.y);
			point.addParent(lines[0]);
			point.addParent(lines[lines.length - 1]);
			obstacles.push(point);
		}
		createPoly([900,1100,  1100,1100, 1100,1110,  900,1110],  true);
		createPoly([600,1210,  600,1220,  710,1220,   710,1210]);
		createPoly([1300,900,  1400,1000, 1300,1000], true);
		createPoly([1500,900,  1510,900,  1510,600,   1500,600]);
		createPoly([1600,860,  1590,860,  1590,600,   1600,600], true);
		createPoly([980,1220,  900,1180,  900,1170,   1100,1170, 1100,1180, 1020,1220], true);
		createPoly([200,1510,  200,1500,  2000,1500,  2000,1510],  true);
		createPoly([1300,1315, 1260,1250, 1300,1340,  1340,1250]);
		createPoly([1400,1300, 1360,1250, 1400,1320,  1440,1250]);
		createPoly([1500,1285, 1460,1250, 1500,1320,  1540,1250]);
		createPoly([1600,1270, 1560,1250, 1600,1320,  1640,1250]);
		createPoly([1600,1100, 1560,1150, 1600,1080,  1640,1150], true);

		//add input bindings
		var keys = { pressed: {} };
		var KEY = { W: 87, A: 65, S: 83, D: 68, R: 82, G: 71, SHIFT: 16, SPACE: 32 };
		var JUMP_KEY = KEY.SPACE;
		$(document).on('keydown', function(evt) {
			if(!keys[evt.which]) {
				keys[evt.which] = true;
				keys.pressed[evt.which] = true;
			}
		});
		$(document).on('keyup', function(evt) {
			if(keys[evt.which]) {
				keys[evt.which] = false;
				keys.pressed[evt.which] = false;
			}
		});
		$(document).on('mousedown', function(evt) {
			grapples.push(player.shootGrapple(evt.clientX + camera.x, evt.clientY + camera.y));
		});

		function everyFrame(ms) {
			tick(ms);
			camera.x = player.pos.x - width / 2;
			camera.y = player.pos.y - height / 2;
			render();
		}

		var interruptionsLastFrame = [];
		function tick(ms) {
			var i, j, interruption, friction = 1;
			for(i = 0; i < grapples.length; i++) {
				if(!grapples[i].isDead && !grapples[i].isLatched) {
					var earliestGrappleCollision = null;
					grapples[i].tick(ms, friction);
					for(j = 0; j < obstacles.length; j++) {
						var collision = obstacles[j].checkForCollisionWithMovingPoint(grapples[i]);
						if(collision && (!earliestGrappleCollision || earliestGrappleCollision.distPreContact > collision.distPreContact)) {
							earliestGrappleCollision = collision;
						}
					}
					if(earliestGrappleCollision) {
						grapples[i].latchTo(earliestGrappleCollision.posOnContact.x, earliestGrappleCollision.posOnContact.y);
					}
				}
			}
			player.applyForce(0, 600); //gravity
			if(keys[KEY.A]) { player.applyForce(-400, 0); }
			if(keys[KEY.D]) { player.applyForce(400, 0); }
			if(keys[KEY.W]) { player.applyForce(0, -400); }
			if(keys[KEY.S]) { player.applyForce(0, 400); }
			if(keys.pressed[JUMP_KEY]) {
				for(i = 0; i < interruptionsLastFrame.length; i++) {
					interruption = interruptionsLastFrame[i];
					if(interruption.interruptionType === 'collision') {
						keys.pressed[JUMP_KEY] = false;
						player.jump(interruption.jumpDir.x, interruption.jumpDir.y);
						break;
					}
				}
			}
			player.tick(ms, friction);
			var interruptionsThisFrame = [];
			interruption = null;
			for(i = 0; i <= 6; i++) {
				if(i === 6) {
					interruption = {
						interruptionType: 'limit',
						posOnContact: { x: player.pos.prev.x, y: player.pos.prev.y },
						posAfterContact: { x: player.pos.prev.x, y: player.pos.prev.y },
						velAfterContact: { x: 0, y: 0 }
					};
				}
				else {
					interruption = findInterruption(interruptionsThisFrame);
				}
				if(interruption) {
					interruptionsThisFrame.push(interruption);
					player.pos.x = interruption.posAfterContact.x;
					player.pos.y = interruption.posAfterContact.y;
					player.pos.prev.x = interruption.posOnContact.x;
					player.pos.prev.y = interruption.posOnContact.y;
					player.vel.x = interruption.velAfterContact.x;
					player.vel.y = interruption.velAfterContact.y;
				}
				else {
					break;
				}
			}
			interruptionsLastFrame = interruptionsThisFrame;
		}

		function findInterruption(prevInterruptions) {
			var i, j, earliestInterruption = null;
			var prevInterruption = (prevInterruptions.length > 0 ? prevInterruptions[prevInterruptions.length - 1] : null);
			for(i = 0; i < obstacles.length; i++) {
				var collision = obstacles[i].checkForCollisionWithMovingCircle(player);
				if(collision && (!earliestInterruption || earliestInterruption.distPreContact > collision.distPreContact) &&
					(!prevInterruption || prevInterruption.interruptionType !== 'collision' || !prevInterruption.obstacle.sameAs(collision.obstacle))) {
					collision.interruptionType = 'collision';
					earliestInterruption = collision;
				}
			}
			for(i = 0; i < grapples.length; i++) {
				var violation = grapples[i].checkForMaxTether();
				if(violation && (!earliestInterruption || earliestInterruption.distPreContact > violation.distPreContact) &&
					(!prevInterruption || prevInterruption.interruptionType !== 'grapple' || !prevInterruption.grapple.sameAs(violation.grapple))) {
					violation.interruptionType = 'grapple';
					earliestInterruption = violation;
				}
			}
			return earliestInterruption;
		}

		function render() {
			var i;
			ctx.fillStyle = '#fff';
			ctx.fillRect(0, 0, width, height);
			for(i = 0; i < grapples.length; i++) {
				grapples[i].render(ctx, camera);
			}
			player.render(ctx, camera);
			for(i = 0; i < obstacles.length; i++) {
				obstacles[i].render(ctx, camera);
			}
		}

		//set up animation frame functionality
		var prevTime;
		requestAnimationFrame(function(time) {
			prevTime = time;
			loop(time);
		});
		function loop(time) {
			var ms = time - prevTime;
			prevTime = time;
			everyFrame(ms, time);
			requestAnimationFrame(loop);
		}
	};
});<|endoftext|>


<commit_before>!function (async, Immutable, linq, path, Pipe, Processor) {
    'use strict';

    var DEFAULT_PROCESSORS = {
            // from: require('./from')
        };

    function PublishJS(immutableOptions) {
        immutableOptions = immutableOptions.withMutations(function (options) {
            options
                .set('basedir', options.get('basedir') || path.resolve('.'))
                .set('output', options.get('output') || 'publish/')
                .set('processors',
                    linq(DEFAULT_PROCESSORS).concat(options.get('processors') || {}).run()
                )
                .update('cache', function (cache) {
                    return (cache === false || cache) ? cache : new require('./filesystemcache');
                });
        });

        this.options = immutableOptions.toJS();
        this._options = immutableOptions;

        var actions = this._actions = {},
            processors = this.options.processors;

        Object.getOwnPropertyNames(processors).forEach(function (name) {
            var CustomProcessor = processors[name];

            if (typeof CustomProcessor !== 'function') {
                throw new Error('options.processors["' + name + '"] should be a function, instead of ' + CustomProcessor);
            }

            actions[name] = function () {
                var args = [].slice.call(arguments),
                    files = args.shift() || {},
                    callback = args.pop(),
                    options = this.options,
                    processor = new CustomProcessor();

                if (!(processor instanceof Processor)) {
                    return callback(new Error('options.processors["' + name + '"] must subclass Processor'));
                }

                try {
                    processor._run(
                        name,
                        options,
                        options.pipeID + '.' + options.actionID++,
                        files,
                        args,
                        callback
                    );
                } catch (ex) {
                    callback(ex);
                }
            };
        });
    }

    PublishJS.prototype.build = function (tasks, callback) {
        var that = this;

        if (typeof tasks === 'function') {
            tasks = [tasks];
        }

        async.series(linq(tasks).toArray(function (fn, nameOrIndex) {
            return function (callback) {
                fn.call(that, that._createPipe(nameOrIndex), callback);
            };
        }).run(), callback);
    };

    PublishJS.prototype._createPipe = function (pipeID) {
        return new Pipe(
            this._actions,
            this._options
                .set('actionID', 0)
                .set('pipeID', pipeID)
                .toJS()
        );
    };

    module.exports = function (options) {
        options = Immutable.Map(options).withMutations(function (options) {
            options._nextActionID = 0;
            options._nextPipeID = 0;
        });

        return new PublishJS(options);
    };
}(
    require('async'),
    require('immutable'),
    require('async-linq'),
    require('path'),
    require('./pipe'),
    require('./processor')
);<commit_msg>options.cache support string and cache provider<commit_after>!function (async, FileSystemCache, Immutable, linq, path, Pipe, Processor) {
    'use strict';

    var DEFAULT_PROCESSORS = {
            // from: require('./from')
        };

    function PublishJS(immutableOptions) {
        immutableOptions = immutableOptions.withMutations(function (options) {
            options
                .set('basedir', options.get('basedir') || path.resolve('.'))
                .set('output', options.get('output') || 'publish/')
                .set('processors',
                    linq(DEFAULT_PROCESSORS).concat(options.get('processors') || {}).run()
                )
                .update('cache', function (cache) {
                    if (cache === false) {
                        return cache;
                    } else if (!cache) {
                        return new FileSystemCache();
                    } else if (typeof cache === 'string') {
                        return new FileSystemCache({ tempdir: cache });
                    } else if (cache instanceof require('./cacheprovider')) {
                        return cache;
                    } else {
                        throw new Error('cache must either be string or base from CacheProvider');
                    }
                });
        });

        this.options = immutableOptions.toJS();
        this._options = immutableOptions;

        var actions = this._actions = {},
            processors = this.options.processors;

        Object.getOwnPropertyNames(processors).forEach(function (name) {
            var CustomProcessor = processors[name];

            if (typeof CustomProcessor !== 'function') {
                throw new Error('options.processors["' + name + '"] should be a function, instead of ' + CustomProcessor);
            }

            actions[name] = function () {
                var args = [].slice.call(arguments),
                    files = args.shift() || {},
                    callback = args.pop(),
                    options = this.options,
                    processor = new CustomProcessor();

                if (!(processor instanceof Processor)) {
                    return callback(new Error('options.processors["' + name + '"] must subclass Processor'));
                }

                try {
                    processor._run(
                        name,
                        options,
                        options.pipeID + '.' + options.actionID++,
                        files,
                        args,
                        callback
                    );
                } catch (ex) {
                    callback(ex);
                }
            };
        });
    }

    PublishJS.prototype.build = function (tasks, callback) {
        var that = this;

        if (typeof tasks === 'function') {
            tasks = [tasks];
        }

        async.series(linq(tasks).toArray(function (fn, nameOrIndex) {
            return function (callback) {
                fn.call(that, that._createPipe(nameOrIndex), callback);
            };
        }).run(), callback);
    };

    PublishJS.prototype._createPipe = function (pipeID) {
        return new Pipe(
            this._actions,
            this._options
                .set('actionID', 0)
                .set('pipeID', pipeID)
                .toJS()
        );
    };

    module.exports = function (options) {
        options = Immutable.Map(options).withMutations(function (options) {
            options._nextActionID = 0;
            options._nextPipeID = 0;
        });

        return new PublishJS(options);
    };
}(
    require('async'),
    require('./filesystemcache'),
    require('immutable'),
    require('async-linq'),
    require('path'),
    require('./pipe'),
    require('./processor')
);<|endoftext|>


<commit_before>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Store Bot Client Info #3",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Bot Client Control",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
	const info = ['Total Amount of Channels', 'Total Amount of Emojis', 'Bot\'s Previous Pings', 'Uptime in Days', 'Uptime in Days (Rounded)', 'Memory (RAM) Usage'];
	return `${info[parseInt(data.info)]}`;
},

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
	const type = parseInt(data.storage);
	if(type !== varType) return;
	const info = parseInt(data.info);
	let dataType = 'Unknown Type';
	switch(info) {
		case 0:
			dataType = "Number";
			break;
		case 1:
			dataType = "Number";
			break;
		case 2:
			dataType = "Number";
			break;
		case 3:
			dataType = "Time";
			break;
		case 4:
			dataType = "Time";
			break;
		case 5:
			dataType = "Number";
			break;
	}
	return ([data.varName2, dataType]);
},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["info", "storage", "varName2"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

			Mod Info:

			Created by EGGSY!

	Source Info:

	<select id="info" class="round">
		<option value="0">Total Amount of Channels</option>
		<option value="1">Total Amount of Emojis</option>
		<option value="2">Bot's Previous Pings</option>
		<option value="3">Uptime in Days</option>
		<option value="4">Uptime in Days (Rounded)</option>
		<option value="5">Memory (RAM) Usage</option>
	</select>

		Store In:

		<select id="storage" class="round">
			${data.variables[1]}
		</select>

		Variable Name:

		<input id="varName2" class="round" type="text">

`
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.messageChange(document.getElementById('message'), 'varNameContainer')
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {
	const data = cache.actions[cache.index];
	const botClient = this.getDBM().Bot.bot;
	const info = parseInt(data.info);
	const msToDay = (1000*60*60*24);
	if(!botClient) {
		this.callNextAction(cache);
		return;
	}
	switch(info) {
		case 0:
			result = botClient.channels.size;
			break;
		case 1:
			result = botClient.emojis.size;
			break;
		case 2:
			result = botClient.pings;
			break;
		case 3:
			result = botClient.uptime/msToDay;
			break;
		case 4:
			result = Math.floor(botClient.uptime/msToDay);
			break;
		case 5:
			result = "%" + ((process.memoryUsage().heapUsed / 1024) / 1024).toFixed(2);
			break;
		default:
		break;
	}
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName2 = this.evalMessage(data.varName2, cache);
		this.storeValue(result, storage, varName2, cache);
	}
	this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module, thanks to Lasse btw!
<commit_msg>Added Compatiblity with DBM Mod Manager!<commit_after>module.exports = {

//---------------------------------------------------------------------
// Action Name
//
// This is the name of the action displayed in the editor.
//---------------------------------------------------------------------

name: "Store Bot Client Info #3",

//---------------------------------------------------------------------
// Action Section
//
// This is the section the action will fall into.
//---------------------------------------------------------------------

section: "Bot Client Control",

//---------------------------------------------------------------------
// Action Subtitle
//
// This function generates the subtitle displayed next to the name.
//---------------------------------------------------------------------

subtitle: function(data) {
	const info = ['Total Amount of Channels', 'Total Amount of Emojis', 'Bot\'s Previous Pings', 'Uptime in Days', 'Uptime in Days (Rounded)', 'Memory (RAM) Usage'];
	return `${info[parseInt(data.info)]}`;
},

//---------------------------------------------------------------------
	 // DBM Mods Manager Variables (Optional but nice to have!)
	 //
	 // These are variables that DBM Mods Manager uses to show information
	 // about the mods for people to see in the list.
	 //---------------------------------------------------------------------

	 // Who made the mod (If not set, defaults to "DBM Mods")
	 author: "EGGSY",

	 // The version of the mod (Defaults to 1.0.0)
	 version: "1.0.3",

	 // A short description to show on the mod line for this mod (Must be on a single line)
	 short_description: "Stores more Bot Client Information by EGGSY",

	 // If it depends on any other mods by name, ex: WrexMODS if the mod uses something from WrexMods

	 //---------------------------------------------------------------------

//---------------------------------------------------------------------
// Action Storage Function
//
// Stores the relevant variable info for the editor.
//---------------------------------------------------------------------

variableStorage: function(data, varType) {
	const type = parseInt(data.storage);
	if(type !== varType) return;
	const info = parseInt(data.info);
	let dataType = 'Unknown Type';
	switch(info) {
		case 0:
			dataType = "Number";
			break;
		case 1:
			dataType = "Number";
			break;
		case 2:
			dataType = "Number";
			break;
		case 3:
			dataType = "Time";
			break;
		case 4:
			dataType = "Time";
			break;
		case 5:
			dataType = "Number";
			break;
	}
	return ([data.varName2, dataType]);
},

//---------------------------------------------------------------------
// Action Fields
//
// These are the fields for the action. These fields are customized
// by creating elements with corresponding IDs in the HTML. These
// are also the names of the fields stored in the action's JSON data.
//---------------------------------------------------------------------

fields: ["info", "storage", "varName2"],

//---------------------------------------------------------------------
// Command HTML
//
// This function returns a string containing the HTML used for
// editting actions.
//
// The "isEvent" parameter will be true if this action is being used
// for an event. Due to their nature, events lack certain information,
// so edit the HTML to reflect this.
//
// The "data" parameter stores constants for select elements to use.
// Each is an array: index 0 for commands, index 1 for events.
// The names are: sendTargets, members, roles, channels,
//                messages, servers, variables
//---------------------------------------------------------------------

html: function(isEvent, data) {
	return `

			Mod Info:

			Created by EGGSY!

	Source Info:

	<select id="info" class="round">
		<option value="0">Total Amount of Channels</option>
		<option value="1">Total Amount of Emojis</option>
		<option value="2">Bot's Previous Pings</option>
		<option value="3">Uptime in Days</option>
		<option value="4">Uptime in Days (Rounded)</option>
		<option value="5">Memory (RAM) Usage</option>
	</select>

		Store In:

		<select id="storage" class="round">
			${data.variables[1]}
		</select>

		Variable Name:

		<input id="varName2" class="round" type="text">

`
},

//---------------------------------------------------------------------
// Action Editor Init Code
//
// When the HTML is first applied to the action editor, this code
// is also run. This helps add modifications or setup reactionary
// functions for the DOM elements.
//---------------------------------------------------------------------

init: function() {
	const {glob, document} = this;

	glob.messageChange(document.getElementById('message'), 'varNameContainer')
},

//---------------------------------------------------------------------
// Action Bot Function
//
// This is the function for the action within the Bot's Action class.
// Keep in mind event calls won't have access to the "msg" parameter,
// so be sure to provide checks for variable existance.
//---------------------------------------------------------------------

action: function(cache) {
	const data = cache.actions[cache.index];
	const botClient = this.getDBM().Bot.bot;
	const info = parseInt(data.info);
	const msToDay = (1000*60*60*24);
	if(!botClient) {
		this.callNextAction(cache);
		return;
	}
	switch(info) {
		case 0:
			result = botClient.channels.size;
			break;
		case 1:
			result = botClient.emojis.size;
			break;
		case 2:
			result = botClient.pings;
			break;
		case 3:
			result = botClient.uptime/msToDay;
			break;
		case 4:
			result = Math.floor(botClient.uptime/msToDay);
			break;
		case 5:
			result = "%" + ((process.memoryUsage().heapUsed / 1024) / 1024).toFixed(2);
			break;
		default:
		break;
	}
	if(result !== undefined) {
		const storage = parseInt(data.storage);
		const varName2 = this.evalMessage(data.varName2, cache);
		this.storeValue(result, storage, varName2, cache);
	}
	this.callNextAction(cache);
},

//---------------------------------------------------------------------
// Action Bot Mod
//
// Upon initialization of the bot, this code is run. Using the bot's
// DBM namespace, one can add/modify existing functions if necessary.
// In order to reduce conflictions between mods, be sure to alias
// functions you wish to overwrite.
//---------------------------------------------------------------------

mod: function(DBM) {
}

}; // End of module, thanks to Lasse btw!
<|endoftext|>


<commit_before>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/dom", "dojo/dom-class", "dojo/dom-construct", "dojo/query!css3", "dojo/dom-style", "dojo/on",
	"d3/d3",
	"dojo/text!./templates/D3StackedBarChart.html"
], function(declare, lang,
			dom, domClass, domConstruct, domQuery, domStyle, on,
			d3,
			Template){

	return declare([], {
		data: null,
		templateString: Template,

		constructor: function(target){
			this.node = domConstruct.place(this.templateString, target, "only");

			this.currentSort = "label";
			this.ascendSort = true;
			this.normalize = false;

			this.drawTargetParams = {
				target: this.node,
				margins: [10, 0, 0, 30]
			};
			var drawTarget = this.prepareSVGDrawTarget(this.drawTargetParams);
			this.chart = drawTarget.chart;
			this.canvas = drawTarget.canvas;
			this.canvasSize = drawTarget.canvas_size;

			var self = this;
			var scaleToggle = domQuery(".chart-wrapper .scale li");
			var sortToggle = domQuery(".chart-wrapper .sort li");

			// Set up the scale toggle
			if(scaleToggle != null){
				scaleToggle.on('click', function(evt){
					scaleToggle.removeClass("active");
					self.normalize = evt.srcElement.className === "normalize";
					domClass.add(evt.srcElement, "active");

					self.scale(function(){
						return self.sort();
					});
				});
			}

			// Set up the sort controls
			if(sortToggle != null){
				sortToggle.on('click', function(evt){
					sortToggle.removeClass("active");
					domClass.add(evt.srcElement, "active");

					return self.sort();
				});
			}
		},

		processData: function(data){

			this.data = data.map((d, i) => ({
				"index": i,
				"label": d.label,
				"total": parseInt(d.total),
				"dist": d.dist,
				"phenotypes": d.phenotypes
			}));
		},

		render: function(){

			// remove existing bars and yAxis
			d3.select("g.y").remove();
			d3.selectAll("g.bar").remove();

			// reset scale params
			this.normalize = domQuery(".chart-wrapper .scale .active")[0].className.split(" ")[0] === "normalize" || false;
			if(this.normalize){
				this.maxValue = 100;
			}else{
				this.maxValue = this.data.map((d) => d.total || 0)
					.reduce((a, b) => Math.max(a, b));
			}

			// reset sort condition
			var sortToggle = domQuery(".chart-wrapper .sort li");
			sortToggle.removeClass("active");
			domClass.add(domQuery(".chart-wrapper .sort .label")[0], "active");

			// axis
			this.pf_y_scale = d3.scale.linear().range([0, this.canvasSize.height]).domain([this.maxValue, 0]);
			this.pf_x_scale = d3.scale.linear().range([0, this.canvasSize.width]).domain([0, this.data.length]);

			// draw bars
			this.canvas.selectAll("g.bar").data(this.data).enter().append("g").attr("class", "bar");
			this.bars = this.canvas.selectAll("g.bar").data(this.data);
			this.tooltipLayer = d3.select("body").append("div")
				.attr("class", "tooltip")
				.style("opacity", 0);

			var self = this;

			this.full_barWidth = self.pf_x_scale(1);
			this.drawn_barWidth = this.full_barWidth * .525;
			this.center_correction = (this.full_barWidth - this.drawn_barWidth) / 2;

			this.yAxis = d3.svg.axis()
				.scale(this.pf_y_scale)
				.orient("left")
				.tickPadding(0).tickSize(0);

			this.chart.append("g")
				.attr("transform", lang.replace('translate({0},{1})',[this.drawTargetParams.margins[3], this.drawTargetParams.margins[0]]))
				.call(this.yAxis)
				.attr("class", "y axis");

			this.seriesSize = this.data.map(d => d['dist'].length).reduce((a, b) => Math.max(a, b));
			for(var index = 0; index < this.seriesSize; index++){

				self.bars.append("rect")
					.attr("class", "block-" + index)
					.attr("y", d =>{
						var ancestorHeight = self.barHeight(d3.sum(d['dist'].slice(0, index)), d.total);
						return Math.round(self.canvasSize.height - self.barHeight(d['dist'][index], d.total) - ancestorHeight);
					})
					.attr("x", (d, i) => self.barPosition(i))
					.attr("width", () => self.barWidth())
					.attr("height", d => Math.round(self.barHeight(d['dist'][index], d.total)))
					//.on("click", {})
					.on("mouseover", d =>{
						self.tooltipLayer.transition()
							.duration(200)
							.style("opacity", .95);
						// console.log(d);
						var content = lang.replace('Antibiotic: {0}
Phenotype: {1}
Count: {2}',[d.label, d.phenotypes[index]], d['dist'][index]);
						self.tooltipLayer.html(content)
							.style("left", d3.event.pageX + "px")
							.style("top", (d3.event.pageY - 28) + "px")
					})
					.on("mouseout", () => self.tooltipLayer.transition()
						.duration(500)
						.style("opacity", 0)
					);
			}

			// Place the text. We have a little height adjustment on the dy
			// to make sure text is centered in the block rather than set
			// along the baseline.

			this.bars.append("text").text(d => d.label)
				.attr("y", Math.round(this.canvasSize.height - 11))
				.attr("x", (d, i) => self.textPosition(i))
				.attr("transform", (d, i) =>{
					var y = Math.round(self.canvasSize.height - 11);
					var x = self.textPosition(i);
					return lang.replace('rotate(270, {0}, {1})', [x, y]);
				})
				.attr("dy", ".35em");

		},

		textPosition: function(index){
			return Math.floor((this.full_barWidth * index) + this.drawn_barWidth);
		},
		barPosition: function(index){
			return Math.floor(this.full_barWidth * index + this.center_correction);
		},
		barWidth: function(){
			return Math.floor(this.drawn_barWidth);
		},
		barHeight: function(value, total){
			if(this.normalize){
				return this.canvasSize.height - this.pf_y_scale((value / total) * 100);
			}else{
				return this.canvasSize.height - this.pf_y_scale(value);
			}
		},
		scale: function(){

			if(this.normalize){
				this.maxValue = 100;
			}else{
				this.maxValue = this.data.map((d) => d.total || 0)
					.reduce((a, b) => Math.max(a, b));
			}

			// update axis
			this.pf_y_scale = d3.scale.linear().range([0, this.canvasSize.height]).domain([this.maxValue, 0]);
			this.yAxis = d3.svg.axis().scale(this.pf_y_scale).orient("left").tickPadding(0).tickSize(0);
			this.chart.select("g.y").transition().duration(600).call(this.yAxis);

			// update bars
			for(var index = 0; index < this.seriesSize; index++){
				this.bars.select(lang.replace('rect.block-{0}', [index]))
					.transition().duration(600)
					.attr("y", (d) =>{
						var ancestorHeight = this.barHeight(d3.sum(d['dist'].slice(0, index)), d.total);
						return Math.round(this.canvasSize.height - this.barHeight(d['dist'][index], d.total) - ancestorHeight);
					})
					.attr("height", d => Math.round(this.barHeight(d['dist'][index], d.total)));
			}
		},
		sort: function(){
			var self = this;

			var sortCriteria = domQuery(".chart-wrapper .sort .active")[0].className.split(" ")[0];

			if(sortCriteria === this.currentSort){
				this.ascendSort = !this.ascendSort;
			}else{
				this.currentSort = sortCriteria;
			}

			if(this.currentSort === "label"){
				this.bars.sort(function(a, b){
					var orderCode = 0;
					if(a.label  b.label){
						orderCode = 1;
					}

					if (!self.ascendSort) {
						orderCode = orderCode * -1;
					}
					return orderCode;
				});
			} else if (this.currentSort === "value"){
				this.bars.sort(function(a, b){
					var aValue = self.barHeight(a['dist'][0], a.total);
					var bValue = self.barHeight(b['dist'][0], b.total);

					var orderCode = aValue - bValue;
					if(!self.ascendSort){
						orderCode = orderCode * -1;
					}
					return orderCode;
				})
			}

			for(var index = 0; index < this.seriesSize; index++){
				this.bars.select(lang.replace('rect.block-{0}',[index]))
					.transition().duration(600)
					.delay((d, i) => 10 * i)
					.attr("x", (d, i) => self.barPosition(i));
			}

			this.bars.select("text").transition().duration(600)
				.delay((d, i) => 10 * i)
				.attr("x", (d, i) => self.textPosition(i))
				.attr("transform", (d, i) =>{
					var y = Math.round(self.canvasSize.height - 11);
					var x = this.pf_x_scale(i) + self.pf_x_scale(1) / 2;
					return lang.replace('rotate(270, {0}, {1})',[x, y]);
				})

		},

		renderLegend: function(legend){
			d3.select("p.legend").selectAll("svg")
				.data(legend)
				.insert("circle")
				.attr("cx", 8).attr("cy", 8).attr("r", 8)
				.attr("class", (d, i) => "bar" + (i + 1) + "-sample");

			d3.select("p.legend").selectAll("span")
				.data(legend)
				.text(d => d);
		},
		prepareSVGDrawTarget: function(params){

			var chartSize = params.size || this.getContainerSize(params.target);
			var chartMargin = params.margins || [0, 0, 0, 0];

			var canvasSize = {
				width: chartSize.width - chartMargin[1] - chartMargin[3],
				height: chartSize.height - chartMargin[0] - chartMargin[2]
			};

			var chart = d3.select(".chart")
				.insert("svg", ":first-child")
				.attr("class", "svgChartContainer")
				.attr("width", chartSize.width)
				.attr("height", chartSize.height);

			var canvas = chart.append("g")
				.attr("class", "svgChartCanvas")
				.attr("width", canvasSize.width)
				.attr("height", canvasSize.height)
				.attr("transform", "translate(" + chartMargin[3] + "," + chartMargin[0] + ")");

			return {
				"chart": chart,
				"canvas": canvas,
				"canvas_size": canvasSize,
				"chart_size": chartSize
			};
		},
		getContainerSize: function(){
			var container = domQuery(".chart", this.node)[0] || null;

			if(container){
				return {
					width: domStyle.get(container, "width"),
					height: domStyle.get(container, "height")
				};
			}else{
				console.error("Cannot find chart Dom Node");
				return {
					width: 0,
					height: 0
				};
			}
		},
		resize: function(){
			// TODO: catch event and resize
			console.log("resizing...");
		}
	})
});<commit_msg>replace arrow function to anonymous function due to Safari compatibility.<commit_after>define([
	"dojo/_base/declare", "dojo/_base/lang",
	"dojo/dom", "dojo/dom-class", "dojo/dom-construct", "dojo/query!css3", "dojo/dom-style", "dojo/on",
	"d3/d3",
	"dojo/text!./templates/D3StackedBarChart.html"
], function(declare, lang,
			dom, domClass, domConstruct, domQuery, domStyle, on,
			d3,
			Template){

	return declare([], {
		data: null,
		templateString: Template,

		constructor: function(target){
			this.node = domConstruct.place(this.templateString, target, "only");

			this.currentSort = "label";
			this.ascendSort = true;
			this.normalize = false;

			this.drawTargetParams = {
				target: this.node,
				margins: [10, 0, 0, 30]
			};
			var drawTarget = this.prepareSVGDrawTarget(this.drawTargetParams);
			this.chart = drawTarget.chart;
			this.canvas = drawTarget.canvas;
			this.canvasSize = drawTarget.canvas_size;

			var self = this;
			var scaleToggle = domQuery(".chart-wrapper .scale li");
			var sortToggle = domQuery(".chart-wrapper .sort li");

			// Set up the scale toggle
			if(scaleToggle != null){
				scaleToggle.on('click', function(evt){
					scaleToggle.removeClass("active");
					var target = evt.srcElement || evt.target;

					self.normalize = target.className == "normalize";
					domClass.add(target, "active");

					self.scale(function(){
						return self.sort();
					});
				});
			}

			// Set up the sort controls
			if(sortToggle != null){
				sortToggle.on('click', function(evt){
					sortToggle.removeClass("active");
					domClass.add(evt.srcElement || evt.target, "active");

					return self.sort();
				});
			}
		},

		processData: function(data){

			this.data = data.map(function(d, i){
				return {
					"index": i,
					"label": d.label,
					"total": parseInt(d.total),
					"dist": d.dist,
					"phenotypes": d.phenotypes
				}
			});
		},

		render: function(){

			// remove existing bars and yAxis
			d3.select("g.y").remove();
			d3.selectAll("g.bar").remove();

			// reset scale params
			this.normalize = domQuery(".chart-wrapper .scale .active")[0].className.split(" ")[0] === "normalize" || false;
			if(this.normalize){
				this.maxValue = 100;
			}else{
				this.maxValue = this.data.map(function(d){
					return d.total || 0
				}).reduce(function(a, b){
					return Math.max(a, b)
				});
			}

			// reset sort condition
			var sortToggle = domQuery(".chart-wrapper .sort li");
			sortToggle.removeClass("active");
			domClass.add(domQuery(".chart-wrapper .sort .label")[0], "active");

			// axis
			this.pf_y_scale = d3.scale.linear().range([0, this.canvasSize.height]).domain([this.maxValue, 0]);
			this.pf_x_scale = d3.scale.linear().range([0, this.canvasSize.width]).domain([0, this.data.length]);

			// draw bars
			this.canvas.selectAll("g.bar").data(this.data).enter().append("g").attr("class", "bar");
			this.bars = this.canvas.selectAll("g.bar").data(this.data);
			this.tooltipLayer = d3.select("body").append("div")
				.attr("class", "tooltip")
				.style("opacity", 0);

			var self = this;

			this.full_barWidth = self.pf_x_scale(1);
			this.drawn_barWidth = this.full_barWidth * .525;
			this.center_correction = (this.full_barWidth - this.drawn_barWidth) / 2;

			this.yAxis = d3.svg.axis()
				.scale(this.pf_y_scale)
				.orient("left")
				.tickPadding(0).tickSize(0);

			this.chart.append("g")
				.attr("transform", lang.replace('translate({0},{1})', [this.drawTargetParams.margins[3], this.drawTargetParams.margins[0]]))
				.call(this.yAxis)
				.attr("class", "y axis");

			this.seriesSize = this.data.map(function(d){
				return d['dist'].length
			})
				.reduce(function(a, b){
					return Math.max(a, b)
				});
			for(var index = 0; index < this.seriesSize; index++){

				self.bars.append("rect")
					.attr("class", "block-" + index)
					.attr("y", function(d){
						var ancestorHeight = self.barHeight(d3.sum(d['dist'].slice(0, index)), d.total);
						return Math.round(self.canvasSize.height - self.barHeight(d['dist'][index], d.total) - ancestorHeight);
					})
					.attr("x", function(d, i){
						return self.barPosition(i)
					})
					.attr("width", function(){
						return self.barWidth()
					})
					.attr("height", function(d){
						return Math.round(self.barHeight(d['dist'][index], d.total))
					})
					//.on("click", {})
					.on("mouseover", function(d){
						self.tooltipLayer.transition()
							.duration(200)
							.style("opacity", .95);
						// console.log(d);
						var content = lang.replace('Antibiotic: {0}
Phenotype: {1}
Count: {2}', [d.label, d.phenotypes[index]], d['dist'][index]);
						self.tooltipLayer.html(content)
							.style("left", d3.event.pageX + "px")
							.style("top", (d3.event.pageY - 28) + "px")
					})
					.on("mouseout", function(){
						self.tooltipLayer.transition()
							.duration(500)
							.style("opacity", 0)
					});
			}

			// Place the text. We have a little height adjustment on the dy
			// to make sure text is centered in the block rather than set
			// along the baseline.

			this.bars.append("text").text(function(d){
				return d.label
			})
				.attr("y", Math.round(this.canvasSize.height - 11))
				.attr("x", function(d, i){
					return self.textPosition(i)
				})
				.attr("transform", function(d, i){
					var y = Math.round(self.canvasSize.height - 11);
					var x = self.textPosition(i);
					return lang.replace('rotate(270, {0}, {1})', [x, y]);
				})
				.attr("dy", ".35em");

		},

		textPosition: function(index){
			return Math.floor((this.full_barWidth * index) + this.drawn_barWidth);
		},
		barPosition: function(index){
			return Math.floor(this.full_barWidth * index + this.center_correction);
		},
		barWidth: function(){
			return Math.floor(this.drawn_barWidth);
		},
		barHeight: function(value, total){
			if(this.normalize){
				return this.canvasSize.height - this.pf_y_scale((value / total) * 100);
			}else{
				return this.canvasSize.height - this.pf_y_scale(value);
			}
		},
		scale: function(){

			if(this.normalize){
				this.maxValue = 100;
			}else{
				this.maxValue = this.data.map(function(d){
					return d.total || 0
				})
					.reduce(function(a, b){
						return Math.max(a, b)
					});
			}
			var self = this;

			// update axis
			this.pf_y_scale = d3.scale.linear().range([0, this.canvasSize.height]).domain([this.maxValue, 0]);
			this.yAxis = d3.svg.axis().scale(this.pf_y_scale).orient("left").tickPadding(0).tickSize(0);
			this.chart.select("g.y").transition().duration(600).call(this.yAxis);

			// update bars
			for(var index = 0; index < this.seriesSize; index++){
				this.bars.select(lang.replace('rect.block-{0}', [index]))
					.transition().duration(600)
					.attr("y", function(d){
						var ancestorHeight = self.barHeight(d3.sum(d['dist'].slice(0, index)), d.total);
						return Math.round(self.canvasSize.height - self.barHeight(d['dist'][index], d.total) - ancestorHeight);
					})
					.attr("height", function(d){
						return Math.round(self.barHeight(d['dist'][index], d.total))
					});
			}
		},
		sort: function(){
			var self = this;

			var sortCriteria = domQuery(".chart-wrapper .sort .active")[0].className.split(" ")[0];

			if(sortCriteria === this.currentSort){
				this.ascendSort = !this.ascendSort;
			}else{
				this.currentSort = sortCriteria;
			}

			if(this.currentSort === "label"){
				this.bars.sort(function(a, b){
					var orderCode = 0;
					if(a.label  b.label){
						orderCode = 1;
					}

					if(!self.ascendSort){
						orderCode = orderCode * -1;
					}
					return orderCode;
				});
			}else if(this.currentSort === "value"){
				this.bars.sort(function(a, b){
					var aValue = self.barHeight(a['dist'][0], a.total);
					var bValue = self.barHeight(b['dist'][0], b.total);

					var orderCode = aValue - bValue;
					if(!self.ascendSort){
						orderCode = orderCode * -1;
					}
					return orderCode;
				})
			}

			for(var index = 0; index < this.seriesSize; index++){
				this.bars.select(lang.replace('rect.block-{0}', [index]))
					.transition().duration(600)
					.delay(function(d, i){
						return 10 * i
					})
					.attr("x", function(d, i){
						return self.barPosition(i)
					});
			}

			this.bars.select("text").transition().duration(600)
				.delay(function(d, i){
					return 10 * i
				})
				.attr("x", function(d, i){
					return self.textPosition(i)
				})
				.attr("transform", function(d, i){
					var y = Math.round(self.canvasSize.height - 11);
					var x = self.pf_x_scale(i) + self.pf_x_scale(1) / 2;
					return lang.replace('rotate(270, {0}, {1})', [x, y]);
				})

		},

		renderLegend: function(legend){
			d3.select("p.legend").selectAll("svg")
				.data(legend)
				.insert("circle")
				.attr("cx", 8).attr("cy", 8).attr("r", 8)
				.attr("class", function(d, i){
					return "bar" + (i + 1) + "-sample"
				});

			d3.select("p.legend").selectAll("span")
				.data(legend)
				.text(function(d){
					return d
				});
		},
		prepareSVGDrawTarget: function(params){

			var chartSize = params.size || this.getContainerSize(params.target);
			var chartMargin = params.margins || [0, 0, 0, 0];

			var canvasSize = {
				width: chartSize.width - chartMargin[1] - chartMargin[3],
				height: chartSize.height - chartMargin[0] - chartMargin[2]
			};

			var chart = d3.select(".chart")
				.insert("svg", ":first-child")
				.attr("class", "svgChartContainer")
				.attr("width", chartSize.width)
				.attr("height", chartSize.height);

			var canvas = chart.append("g")
				.attr("class", "svgChartCanvas")
				.attr("width", canvasSize.width)
				.attr("height", canvasSize.height)
				.attr("transform", "translate(" + chartMargin[3] + "," + chartMargin[0] + ")");

			return {
				"chart": chart,
				"canvas": canvas,
				"canvas_size": canvasSize,
				"chart_size": chartSize
			};
		},
		getContainerSize: function(){
			var container = domQuery(".chart", this.node)[0] || null;

			if(container){
				return {
					width: domStyle.get(container, "width"),
					height: domStyle.get(container, "height")
				};
			}else{
				console.error("Cannot find chart Dom Node");
				return {
					width: 0,
					height: 0
				};
			}
		},
		resize: function(){
			// TODO: catch event and resize
			console.log("resizing...");
		}
	})
});<|endoftext|>


<commit_before>async function hologram_app(args) {
/*
visibility("PUBLIC")
base_component_id("hologram")
created_timestamp(-1)
display_name("3d hologram app")
is_app(true)
description('Game app, this will return the game app')
uses_javascript_librararies(["advanced_bundle"])
logo_url("/driver_icons/hologram.png")

*/

    Vue.component('hologram',{
      template: `

({{x}},{{y}}) . ({{width}},{{height}}) ,  {{view_x}}, {{view_y}}, {{videoWidth}}

                  <video
                      style="position: absolute;width:50%;height;50%;"
                      v-on:play="onPlay"
                      id="inputVideo"
                      autoplay
                      muted>
                 </video>

                  <canvas  id="overlay"
                            style="position: absolute;;width:50%;height;50%;"
                  />

      `,
      data: function() {
          return {
              msg: "Test Hologram!",
              car: 1,
              x: -1,
              y: -1,
              width: -1,
              height: -1
              ,
              view_x: 0,
              view_y: 0,
              videoWidth: 0
          }
      }
      ,

      mounted: async function() {
        console.log(faceapi.nets)
        await faceapi.nets.ssdMobilenetv1.loadFromUri('/weights')
        await faceapi.loadMtcnnModel('/weights')
        await faceapi.loadFaceRecognitionModel('/weights')
        await faceapi.nets.faceLandmark68Net.loadFromUri('/weights')
        await faceapi.nets.tinyFaceDetector.loadFromUri('/weights' );

            // Grab elements, create settings, etc.
            var video = document.getElementById('inputVideo');

            // Get access to the camera!
            if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                // Not adding `{ audio: true }` since we only want video now
                navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
                    //video.src = window.URL.createObjectURL(stream);
                    video.srcObject = stream;
                    //video.play();
                });
            }

      },
      methods:
      {
        onPlay: async function ()
        {
            let mm = this

            try {
                const mtcnnForwardParams = {
                     minFaceSize: 200
                }

                const detections = await faceapi.detectSingleFace(
                                        document.getElementById('inputVideo')
                                        ,
                                        new faceapi.TinyFaceDetectorOptions())

                //const mtcnnResults = await faceapi.mtcnn(document.getElementById('inputVideo'), mtcnnForwardParams)

                //faceapi.draw.drawDetections(document.getElementById('overlay'), detections);
                if (detections) {

                    mm.x = Math.floor(detections._box._x)
                    mm.y = Math.floor(detections._box._y)
                    mm.width = Math.floor(detections._box._width)
                    mm.height = Math.floor(detections._box._height)

                    mm.videoWidth = mm.getInnerWidth(document.getElementById("inputVideo"))

                    mm.view_x = -30 + ((1 / mm.videoWidth) * mm.x * 120)
                    //mm.view_y = -35 + ((1 / mm.height) * mm.y * 30)
                    //console.log(JSON.stringify(mm.view_y,null,2))

                }
                //console.log(mm.car++)

            } catch (err) {

            }

            setTimeout(() => mm.onPlay(),100)
        }
        ,

        getInnerWidth: function(elem) {
            return elem.getBoundingClientRect().width
        }

      }

    })
}
<commit_msg>big speedup of hologram<commit_after>async function hologram_app(args) {
/*
visibility("PUBLIC")
base_component_id("hologram")
created_timestamp(-1)
display_name("3d hologram app")
is_app(true)
description('Game app, this will return the game app')
uses_javascript_librararies(["advanced_bundle"])
logo_url("/driver_icons/hologram.png")

*/

    Vue.component('hologram',{
      template: `

({{x}},{{y}}) . ({{width}},{{height}}) ,  {{view_x}}, {{view_y}}, {{videoWidth}}

                  <video
                      style="position: absolute;width:50%;height;50%;"
                      v-on:play="onPlay"
                      id="inputVideo"
                      autoplay
                      muted>
                 </video>

                  <canvas  id="overlay"
                            style="position: absolute;;width:50%;height;50%;"
                  />

      `,
      data: function() {
          return {
              msg: "Test Hologram!",
              car: 1,
              x: -1,
              y: -1,
              width: -1,
              height: -1
              ,
              view_x: 0,
              view_y: 0,
              videoWidth: 0
          }
      }
      ,

      mounted: async function() {
        console.log(faceapi.nets)
        await faceapi.nets.ssdMobilenetv1.loadFromUri('/weights')
        await faceapi.loadMtcnnModel('/weights')
        await faceapi.loadFaceRecognitionModel('/weights')
        await faceapi.nets.faceLandmark68Net.loadFromUri('/weights')
        await faceapi.nets.tinyFaceDetector.loadFromUri('/weights' );

            // Grab elements, create settings, etc.
            var video = document.getElementById('inputVideo');

            // Get access to the camera!
            if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                // Not adding `{ audio: true }` since we only want video now
                navigator.mediaDevices.getUserMedia({ video: true }).then(function(stream) {
                    //video.src = window.URL.createObjectURL(stream);
                    video.srcObject = stream;
                    //video.play();
                });
            }

      },
      methods:
      {
        onPlay: async function ()
        {
            let mm = this

            try {
                const mtcnnForwardParams = {
                     minFaceSize: 200
                }

                const detections = await faceapi.detectSingleFace(
                                        document.getElementById('inputVideo')
                                        ,
                                        new faceapi.TinyFaceDetectorOptions()
                                        ,
                                        mtcnnForwardParams
                                        )

                //const mtcnnResults = await faceapi.mtcnn(document.getElementById('inputVideo'), mtcnnForwardParams)

                //faceapi.draw.drawDetections(document.getElementById('overlay'), detections);
                if (detections) {

                    mm.x = Math.floor(detections._box._x)
                    mm.y = Math.floor(detections._box._y)
                    mm.width = Math.floor(detections._box._width)
                    mm.height = Math.floor(detections._box._height)

                    mm.videoWidth = mm.getInnerWidth(document.getElementById("inputVideo"))

                    mm.view_x = -30 + ((1 / mm.videoWidth) * mm.x * 120)
                    //mm.view_y = -35 + ((1 / mm.height) * mm.y * 30)
                    //console.log(JSON.stringify(mm.view_y,null,2))

                }
                //console.log(mm.car++)

            } catch (err) {

            }

            setTimeout(() => mm.onPlay())
        }
        ,

        getInnerWidth: function(elem) {
            return elem.getBoundingClientRect().width
        }

      }

    })
}
<|endoftext|>


<commit_before>/**
 * Class Year Controller
 */

'use strict';

var ClassYear = require('./classyear.model');
var Attendance = require('../attendance/attendance.model');
var SmallGroup = require('../smallgroup/smallgroup.model');

/**
* @api {get} /api/classyear Index
* @apiName index
* @apiGroup ClassYear
* @apiDescription Get current ClassYear
* @apiPermission public
* @apiSuccess {Model} The model of the current ClassYear
* @apiError (500) UnknownException Could not retrieve ClassYear collection
*/
exports.index = function(req, res) {
  var query = ClassYear.findOne({"current": true});
  if (req.user && req.user.isAdmin){
      query.select('+dayCodes.code')
  }
  return query.exec(function(err, classYear){
  	if(err) { return handleError(res, err); }
    var responseObject = classYear.toObject();
    // Admins should get a day code
    // Generate a day code if one does not already exist
    if (req.user.isAdmin){
        // Admins should get a day code
        // Generate a day code if one does not already exist
        if (classYear.dayCode){
            responseObject.dayCode = classYear.dayCode;
        }
        if (classYear.bonusDayCode){
            responseObject.bonusDayCode = classYear.bonusDayCode;
        }
    }
   	return res.status(200).json(responseObject);
  });
};

// Get a specific class year, Limited to Admins
exports.getClassYear = function(req, res) {
  ClassYear.findOne({
    "semester": req.params.semester
  })
  .select('+dayCodes.code')
  .exec(function (err, classYear){
    if(err) { return handleError(res, err); }
    if (!classYear) return res.send(404);
    var responseObject = classYear.toObject();
    res.json(responseObject);
  })
};

/**
* @api {get} /api/classyear Count Bonus Days
* @apiName countBonusDays
* @apiGroup ClassYear
* @apiDescription Get a specific class year's attendance bonus days
* @apiPermission public
* @apiSuccess {Model} The bonus days of a specific class year
* @apiError (500) UnknownException Could not retrieve ClassYear collection
*/
// NOTE - this controller function is not used
exports.countBonusDays = function(req, res) {
  ClassYear.getCurrent(function (err, classYear){
    if(err) { return handleError(res, err); }
    if (!classYear) return res.send(404);
    var bonusDays  = classYear.dayCodes.reduce(function(previousValue, currentValue) {
      return previousValue + (currentValue.bonusDay ? 1 : 0); // Add 1 to the count for each bonusday in classYear.dayCodes
    }, 0);
    res.json(bonusDays);
  });
};

/**
* @api {post} /api/classyear Create
* @apiName create
* @apiGroup ClassYear
* @apiDescription Create a new ClassYear
* @apiPermission admin
* @apiSuccess {Model} Sends 204 Success response
* @apiError (500) UnknownException Could not retrieve creat ClassYear
*/
exports.create = function(req, res) {
  var semester = req.body.semester;
  if (!semester) return handleError(res, "No Semester Specified");
  ClassYear.findOne({
    "semester": req.body.semester
  }, function(err, classYear){
    if (classYear){
      // Set existing class year as current class year and do not create
      // a new class year
      classYear.current = true;
    }else{
      // Create new class year and set as current
      classYear = new ClassYear(req.body);
      classYear.current = true;
    }
    classYear.save(function(err, classYear){
      if (err) return validationError(res, err);

      // Make sure there are no other current class years
      ClassYear.find({
        "current": true,
        "semester": {$ne : classYear.semester}
      }, function(err, otherClassYears){

        for (var i = 0 ; i < otherClassYears.length ; i++){
          var otherClassYear = otherClassYears[i];
          if (classYear.semester !== otherClassYear.semester){
            otherClassYear.current = false;
            otherClassYear.save();
          }
        }
      });
      ClassYear.getCurrent(function(err, currentClassYear){
          global.currentClassYear = currentClassYear;
          res.send(204);
      });
    });

  })
};

// Update class year
exports.update = function(req, res) {
  ClassYear.findOne({
    "semester": req.params.semester
  },function(err, classYear){
    if(err) { return handleError(res, err); }
    classYear.update(req.body, function(err){
      if(err) { return handleError(res, err); }
      ClassYear.getCurrent(function(err, currentClassYear){
          global.currentClassYear = currentClassYear;
          res.send(204);

      });

    });
  });
};

// Deletes a class year from the DB.
exports.destroy = function(req, res) {
  return ClassYear.findOne({
    "semester": req.params.semester
  }, function(err, classYear){
    classYear.delete();
  });
};

// Generate a daycode or return the current day code for the
// current class year
exports.daycode = function(req, res){
  ClassYear.getCurrentCodes(function(err, classYear){
    if (err) return handleError(res, err);
    var today = new Date();
    today.setHours(0,0,0,0);
    for (var i = 0;i < classYear.dayCodes.length;i++){
      if (today.getTime() === classYear.dayCodes[i].date.getTime()){
        return res.send(200, classYear.dayCodes[i].code);
      }
    }
    //unique code generator, function at the bottom.
    uniqueDayCode(6,function(err,dayCode){
      if (err) return handleError(res, err);
      var code = dayCode;

      classYear.dayCodes.push({
        date: today,
        code: code,
        bonusDay: req.body.bonusDay ? true : false
      });
      return classYear.save(function(err, classYear){
        if (err) return handleError(res, err);
        return res.send(200,code);
      });
    });
  });
};

// Delete a day code from a classyear and the corresponding daycode submission from attendance
// Restricted to admins
// router.delete('/day/:dayCode', auth.hasRole('admin'), controller.deleteDay);
exports.deleteDay = function(req, res){
    var dayCode = req.params.dayCode;

    return ClassYear.findOneAndUpdate({"current": true}, {
        $pull: { dayCodes: {code : dayCode }}
    })
    .select('+dayCodes.code')
    .exec(function(err, classYear){
        if (err) return handleError(res, err);

        return Attendance.remove({code : dayCode}, function (err){
          if (err) return handleError(res, err);
           return res.status(200).json(classYear);
        });
    });
};

// Toggles URP display
exports.displayURP = function(req, res) {
  return ClassYear.getCurrent(function(err, classYear){
    if(err) { return handleError(res, err); }
    return classYear.update(req.body, function(err){
      if(err) { return handleError(res, err); }
      res.send(200);
    });
  });
};

// Toggles URP display
exports.getDisplayURP = function(req, res) {
  return ClassYear.getCurrent(function (err, classYear){
    if(err) { return handleError(res, err); }
    // if no class year is defined then don't show urp
    if(!classYear) {
      res.json({displayURP: false});
    } else {
      res.json({displayURP:classYear.displayURP});
    }
  })
};

function handleError(res, err) {
  return res.send(500, err);
}

function validationError(res, err) {
  return res.status(422).json(err);
}

//Generating non ambigious length sized code.
function generateCode(codeLength){
  var characterOptions = "2346789ABCDEFGHJKMNPQRTUVWXYZ";
  //Non ambigious characters and numbers Remove Some if you think they are ambigious given your font.

  var code = ""; //Simple derivation based on previous code generation code.
  for(var i=0;i<codeLength;i++){
      var character = (Math.floor(Math.random() * characterOptions.length));
      code = code.concat(characterOptions[character.toString()]);
  }
  return code;
}

//Generating unique code.
function uniqueDayCode(codeLength,callback){
  var code = generateCode(codeLength);
  ClassYear.findOne({"dayCodes.code":code})
    .exec(function(err, classYear){
      if (err) return callback("error when getting dayCode",null);
      if(classYear) {
        return uniqueDayCode(codeLength+1,callback);
      }
      else{
        SmallGroup.findOne({"dayCodes.code":code})
          .exec(function(err, smallgroup){
            if (err) return callback("error when getting dayCode",null);
            if(smallgroup){
              return uniqueDayCode(codeLength+1,callback);
            }
            return callback(null,code);
        });
      }
  });
}
<commit_msg>Added APIDoc to two function<commit_after>/**
 * Class Year Controller
 */

'use strict';

var ClassYear = require('./classyear.model');
var Attendance = require('../attendance/attendance.model');
var SmallGroup = require('../smallgroup/smallgroup.model');

/**
* @api {get} /api/classyear Index
* @apiName index
* @apiGroup ClassYear
* @apiDescription Get current ClassYear
* @apiPermission public
* @apiSuccess {Model} The model of the current ClassYear
* @apiError (500) UnknownException Could not retrieve ClassYear collection
*/
exports.index = function(req, res) {
  var query = ClassYear.findOne({"current": true});
  if (req.user && req.user.isAdmin){
      query.select('+dayCodes.code')
  }
  return query.exec(function(err, classYear){
  	if(err) { return handleError(res, err); }
    var responseObject = classYear.toObject();
    // Admins should get a day code
    // Generate a day code if one does not already exist
    if (req.user.isAdmin){
        // Admins should get a day code
        // Generate a day code if one does not already exist
        if (classYear.dayCode){
            responseObject.dayCode = classYear.dayCode;
        }
        if (classYear.bonusDayCode){
            responseObject.bonusDayCode = classYear.bonusDayCode;
        }
    }
   	return res.status(200).json(responseObject);
  });
};

// Get a specific class year, Limited to Admins
exports.getClassYear = function(req, res) {
  ClassYear.findOne({
    "semester": req.params.semester
  })
  .select('+dayCodes.code')
  .exec(function (err, classYear){
    if(err) { return handleError(res, err); }
    if (!classYear) return res.send(404);
    var responseObject = classYear.toObject();
    res.json(responseObject);
  })
};

/**
* @api {get} /api/classyear Count Bonus Days
* @apiName countBonusDays
* @apiGroup ClassYear
* @apiDescription Get a specific class year's attendance bonus days
* @apiPermission public
* @apiSuccess {Model} The bonus days of a specific class year
* @apiError (500) UnknownException Could not retrieve ClassYear collection
*/
// NOTE - this controller function is not used
exports.countBonusDays = function(req, res) {
  ClassYear.getCurrent(function (err, classYear){
    if(err) { return handleError(res, err); }
    if (!classYear) return res.send(404);
    var bonusDays  = classYear.dayCodes.reduce(function(previousValue, currentValue) {
      return previousValue + (currentValue.bonusDay ? 1 : 0); // Add 1 to the count for each bonusday in classYear.dayCodes
    }, 0);
    res.json(bonusDays);
  });
};

/**
* @api {post} /api/classyear Create
* @apiName create
* @apiGroup ClassYear
* @apiDescription Create a new ClassYear
* @apiPermission admin
* @apiSuccess {Model} Sends 204 Success response
* @apiError (500) UnknownException Could not retrieve creat ClassYear
*/
exports.create = function(req, res) {
  var semester = req.body.semester;
  if (!semester) return handleError(res, "No Semester Specified");
  ClassYear.findOne({
    "semester": req.body.semester
  }, function(err, classYear){
    if (classYear){
      // Set existing class year as current class year and do not create
      // a new class year
      classYear.current = true;
    }else{
      // Create new class year and set as current
      classYear = new ClassYear(req.body);
      classYear.current = true;
    }
    classYear.save(function(err, classYear){
      if (err) return validationError(res, err);

      // Make sure there are no other current class years
      ClassYear.find({
        "current": true,
        "semester": {$ne : classYear.semester}
      }, function(err, otherClassYears){

        for (var i = 0 ; i < otherClassYears.length ; i++){
          var otherClassYear = otherClassYears[i];
          if (classYear.semester !== otherClassYear.semester){
            otherClassYear.current = false;
            otherClassYear.save();
          }
        }
      });
      ClassYear.getCurrent(function(err, currentClassYear){
          global.currentClassYear = currentClassYear;
          res.send(204);
      });
    });

  })
};

/**
* @api {post} /api/classyear Update
* @apiName update
* @apiGroup ClassYear
* @apiDescription Update class year
* @apiPermission admin
* @apiSuccess {Model} Sends 204 Success response
* @apiError (500) UnknownException Could not updata data.
*/
exports.update = function(req, res) {
  ClassYear.findOne({
    "semester": req.params.semester
  },function(err, classYear){
    if(err) { return handleError(res, err); }
    classYear.update(req.body, function(err){
      if(err) { return handleError(res, err); }
      ClassYear.getCurrent(function(err, currentClassYear){
          global.currentClassYear = currentClassYear;
          res.send(204);

      });

    });
  });
};

/**
* @api {post} /api/classyear Destory
* @apiName destory
* @apiGroup ClassYear
* @apiDescription Deletes a class year from the DB.
* @apiPermission admin
* @apiSuccess {Model} no response
* @apiError (500) no response.
*/
exports.destroy = function(req, res) {
  return ClassYear.findOne({
    "semester": req.params.semester
  }, function(err, classYear){
    classYear.delete();
  });
};

/**
* @api {post} /api/classyear Daycode
* @apiName daycode
* @apiGroup ClassYear
* @apiDescription Generate a daycode or return the current day code for the current class year
* @apiPermission admin
* @apiSuccess {Model} returning day code for current day
* @apiError (500) UnknownException Could not return a correct code.
*/
exports.daycode = function(req, res){
  ClassYear.getCurrentCodes(function(err, classYear){
    if (err) return handleError(res, err);
    var today = new Date();
    today.setHours(0,0,0,0);
    for (var i = 0;i < classYear.dayCodes.length;i++){
      if (today.getTime() === classYear.dayCodes[i].date.getTime()){
        return res.send(200, classYear.dayCodes[i].code);
      }
    }
    //unique code generator, function at the bottom.
    uniqueDayCode(6,function(err,dayCode){
      if (err) return handleError(res, err);
      var code = dayCode;

      classYear.dayCodes.push({
        date: today,
        code: code,
        bonusDay: req.body.bonusDay ? true : false
      });
      return classYear.save(function(err, classYear){
        if (err) return handleError(res, err);
        return res.send(200,code);
      });
    });
  });
};

// Delete a day code from a classyear and the corresponding daycode submission from attendance
// Restricted to admins
// router.delete('/day/:dayCode', auth.hasRole('admin'), controller.deleteDay);
exports.deleteDay = function(req, res){
    var dayCode = req.params.dayCode;

    return ClassYear.findOneAndUpdate({"current": true}, {
        $pull: { dayCodes: {code : dayCode }}
    })
    .select('+dayCodes.code')
    .exec(function(err, classYear){
        if (err) return handleError(res, err);

        return Attendance.remove({code : dayCode}, function (err){
          if (err) return handleError(res, err);
           return res.status(200).json(classYear);
        });
    });
};

// Toggles URP display
exports.displayURP = function(req, res) {
  return ClassYear.getCurrent(function(err, classYear){
    if(err) { return handleError(res, err); }
    return classYear.update(req.body, function(err){
      if(err) { return handleError(res, err); }
      res.send(200);
    });
  });
};

// Toggles URP display
exports.getDisplayURP = function(req, res) {
  return ClassYear.getCurrent(function (err, classYear){
    if(err) { return handleError(res, err); }
    // if no class year is defined then don't show urp
    if(!classYear) {
      res.json({displayURP: false});
    } else {
      res.json({displayURP:classYear.displayURP});
    }
  })
};

function handleError(res, err) {
  return res.send(500, err);
}

function validationError(res, err) {
  return res.status(422).json(err);
}

//Generating non ambigious length sized code.
function generateCode(codeLength){
  var characterOptions = "2346789ABCDEFGHJKMNPQRTUVWXYZ";
  //Non ambigious characters and numbers Remove Some if you think they are ambigious given your font.

  var code = ""; //Simple derivation based on previous code generation code.
  for(var i=0;i<codeLength;i++){
      var character = (Math.floor(Math.random() * characterOptions.length));
      code = code.concat(characterOptions[character.toString()]);
  }
  return code;
}

//Generating unique code.
function uniqueDayCode(codeLength,callback){
  var code = generateCode(codeLength);
  ClassYear.findOne({"dayCodes.code":code})
    .exec(function(err, classYear){
      if (err) return callback("error when getting dayCode",null);
      if(classYear) {
        return uniqueDayCode(codeLength+1,callback);
      }
      else{
        SmallGroup.findOne({"dayCodes.code":code})
          .exec(function(err, smallgroup){
            if (err) return callback("error when getting dayCode",null);
            if(smallgroup){
              return uniqueDayCode(codeLength+1,callback);
            }
            return callback(null,code);
        });
      }
  });
}
<|endoftext|>