<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Copyright (C) 2017 Max Nikulin */

'use strict';

var AltTong = (function() {
	var currentMenu = new Map();
	var currentValue = null;
	const logPrefix = 'AltTong';

	// currentValue is implicit parameter
	const interceptor = {
		current: null,

		headerRewriter({ requestHeaders }) {
			for (let header of requestHeaders) {
				if (header.name.toLowerCase() === 'accept-language') {
					header.value = currentValue;
					break;
				}
			}
			return { requestHeaders };
		},

		off() {
			if (this.current != null) {
				chrome.webRequest.onBeforeSendHeaders.removeListener(this.current);
				this.current = null;
			}
			return;
		},

		on() {
			if (this.current == null) {
				this.current = this.headerRewriter;
				chrome.webRequest.onBeforeSendHeaders.addListener(
					this.current,
					{ urls: [ 'http://*/*', 'https://*/*' ] },
					[ 'blocking', 'requestHeaders' ]
				);
			}
		}
	};

	// currentValue is an implicit parameter
	const contextMenus = ((interceptor) => {
		const contexts = [ "tab" ];
		const CMIID_DEFAULT = 'cmiid-default';
		const CMIID_CHECKBOX = 'cmiid-checkbox';
		const CMIID_OPTIONS = 'cmiid-options';
		return {
			listener: null,

			configListener({menuItemId}) {
				if (menuItemId === CMIID_OPTIONS) {
					chrome.runtime.openOptionsPage();
				} else {
					console.error(`${logPrefix}: options: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
				}
			},

			checkBoxListener({menuItemId, checked}) {
				if (CMIID_CHECKBOX != menuItemId) { // assert
					console.error(`${logPrefix}: checkbox: context menu item id '${menuItemId}' != '${CMIID_CHECKBOX}'`);
				}

				currentValue = null;
				if (!checked) {
					interceptor.off();
					return;
				}

				if (!currentMenu.has(menuItemId)) {
					console.error(`${logPrefix}: checkbox: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
					return;
				}

				currentValue = currentMenu.get(menuItemId);
				interceptor.on();
			},

			arrayListener({menuItemId}) {
				currentValue = null;
				if (menuItemId === CMIID_DEFAULT) {
					interceptor.off();
					return;
				}

				if (!currentMenu.has(menuItemId)) {
					console.error(`${logPrefix}: array: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
					return;
				}

				currentValue = currentMenu.get(menuItemId);
				interceptor.on();
			},

			setListener(newListener) {
				if (newListener === this.listener) {
					return;
				}
				if (this.listener != null) {
					chrome.contextMenus.onClicked.removeListener(this.listener);
				}
				if (newListener != null) {
					this.listener = newListener;
					chrome.contextMenus.onClicked.addListener(this.listener);
				} else {
					console.error(`${logPrefix}: setListener(null)`);
					interceptor.off();
				}
			},

			createConfig(isDefault) {
				const prefix = isDefault ? '(!) ' : '';
				chrome.contextMenus.create({
					title: prefix + chrome.i18n.getMessage("contextMenuOptionsItem"),
					id: CMIID_OPTIONS,
					contexts
				});

				interceptor.off();
				this.setListener(this.configListener);
			},

			createCheckBox({checked, title}) {
				// Suppress "16" and "32" icons by empty string in manifest.json,
				// otherwise the icon will be overlapped with checkbox.
				const id = CMIID_CHECKBOX;
				const result = chrome.contextMenus.create({
					title: `Alt Tong: ${title}`,
					id,
					contexts,
					type: "checkbox",
					checked
				}, () => this.checkBoxListener({ menuItemId: id, checked }));

				this.setListener(this.checkBoxListener);
				return result;
			},

			createRadioItem({id, checked, title}) {
				return chrome.contextMenus.create(
					{
						title,
						id,
						contexts,
						type: "radio",
						checked
					},
					() => {
						if (checked) {
							this.checkBoxListener({ menuItemId: id, checked });
						}
					}
				);
			},

			createDefaultItem(checked) {
				const result = this.createRadioItem({
					id: CMIID_DEFAULT,
					checked,
					title: chrome.i18n.getMessage("menuDefault")
				});

				this.setListener(this.arrayListener);
				return result;
			}
		};
	})(interceptor);

	function updateContextMenu(newItems, defaultLangs) {
		let removed = browser.contextMenus.removeAll();
		currentMenu.clear();

		if (newItems == null || !(newItems.length > 0)) {
			const isDefault = (newItems.length === 1 && newItems[0].value === defaultLangs);
			removed.then(() => contextMenus.createConfig(isDefault));
			return false;
		}

		const nonDefaultChecked = (currentValue != null) && (
			newItems.length === 1 || newItems.some(item => currentValue === item.value)
		);

		if (newItems.length === 1) {
			removed.then(() => {
				const item = newItems[0];
				currentValue = item.value;
				const id = contextMenus.createCheckBox({
					title: item.title || item.value,
					checked: nonDefaultChecked
				});
				currentMenu.set(id, item.value);
			});
		} else {
			// Not available trough options.html
			// May be tested from debugger
			// AltTong.configure({optionList: [ {value: "fr", title: "Fr"}, {value: "de", title: "De"} ] })

			// FIXME If newItems is string
			removed.then(() => {
				contextMenus.createDefaultItem(!nonDefaultChecked);
				newItems.forEach((item, index) => {
					if (item.value == null || item.value === '') {
						console.error(`${logPrefix}: empty value in updateContextMenu`);;
						return;
					}
					const id = "at-i" + (index + 1);
					const checked = nonDefaultChecked && item.value === currentValue;
					currentMenu.set(id, item.value);
					contextMenus.createRadioItem({
						title: item.title || item.value, // FIXME til , or ;
						id,
						checked
					});
				});
			});
		}
		return true;
	}

	const OPT_STORAGE_OPTION_LIST = "optionList";
	function getOptions() {
		return browser.storage.local.get(OPT_STORAGE_OPTION_LIST);
	}
	function saveOptions(options) {
		return browser.storage.local.set({
			[OPT_STORAGE_OPTION_LIST]: options[OPT_STORAGE_OPTION_LIST]
		});
	}
	function configure(options) {
		if (options != null) {
			return saveOptions(options)
				.then(() => doConfigure(options));
		} else {
			return getOptions().then(options => configure(options));
		}
	}
	function doConfigure(options) {
		return getAcceptLanguages()
			.then(
				langs => updateContextMenu(options.optionList, langs),
				() => updateContextMenu(options.optionList, null)
			).then(null, (e) => { console.error('Alt-Tong: doConfigure', e); });
	}

	function getAcceptLanguages() {
		// browser.i18n.getAcceptLanguages() returns array of language codes,
		// not a header content, so sniff for the actual value.
		return new Promise((resolve, reject) => {
			try {
				const testURL = 'http://localhost/';
				function extractAcceptLanguages({requestHeaders}) {
					var isFakeRequest = false;
					var acceptLanguage;
					for (let header of requestHeaders) {
						if (header.name.toLowerCase() === 'accept-language') {
							acceptLanguage = header.value;
						} else if (header.name.toLowerCase() === 'x-alttong-sniff-header') {
							isFakeRequest = true;
						}
						if (isFakeRequest && acceptLanguage != null) {
							break;
						}
					}
					if (isFakeRequest) {
						chrome.webRequest.onBeforeSendHeaders.removeListener(extractAcceptLanguages);
						resolve(acceptLanguage);
						return { cancel: true, requestHeaders };
					} else {
						return { requestHeaders };
					}
				}
				var fakeRequest = new XMLHttpRequest();
				fakeRequest.addEventListener('load', () => reject(new Error('Failed to catch test XHR')));
				fakeRequest.open('HEAD', testURL);
				fakeRequest.setRequestHeader('X-AltTong-Sniff-Header', 'Accept-Languages');

				const origReject = reject;
				reject = reason => {
					console.error(reason);
					chrome.webRequest.onBeforeSendHeaders.removeListener(extractAcceptLanguages);
					origReject(reason);
				};
				chrome.webRequest.onBeforeSendHeaders.addListener(
					extractAcceptLanguages,
					{ urls: [ testURL ] },
					[ 'blocking', 'requestHeaders' ]
				);
				// For some reason synchronous call of send() results in not caught request.
				// Zero timeout does not work during first loading of this extension.
				// Reload extension works even with zero timeout.
				setTimeout(() => fakeRequest.send(), 20);
			} catch (e) {
				reject(e);
			}
		});
	}

	return { configure, getOptions, getAcceptLanguages, OPT_STORAGE_OPTION_LIST };
})();

AltTong.configure();
<commit_msg>Fix abscence of context menu if config is empty<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* Copyright (C) 2017 Max Nikulin */

'use strict';

var AltTong = (function() {
	var currentMenu = new Map();
	var currentValue = null;
	const logPrefix = 'AltTong';

	// currentValue is implicit parameter
	const interceptor = {
		current: null,

		headerRewriter({ requestHeaders }) {
			for (let header of requestHeaders) {
				if (header.name.toLowerCase() === 'accept-language') {
					header.value = currentValue;
					break;
				}
			}
			return { requestHeaders };
		},

		off() {
			if (this.current != null) {
				chrome.webRequest.onBeforeSendHeaders.removeListener(this.current);
				this.current = null;
			}
			return;
		},

		on() {
			if (this.current == null) {
				this.current = this.headerRewriter;
				chrome.webRequest.onBeforeSendHeaders.addListener(
					this.current,
					{ urls: [ 'http://*/*', 'https://*/*' ] },
					[ 'blocking', 'requestHeaders' ]
				);
			}
		}
	};

	// currentValue is an implicit parameter
	const contextMenus = ((interceptor) => {
		const contexts = [ "tab" ];
		const CMIID_DEFAULT = 'cmiid-default';
		const CMIID_CHECKBOX = 'cmiid-checkbox';
		const CMIID_OPTIONS = 'cmiid-options';
		return {
			listener: null,

			configListener({menuItemId}) {
				if (menuItemId === CMIID_OPTIONS) {
					chrome.runtime.openOptionsPage();
				} else {
					console.error(`${logPrefix}: options: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
				}
			},

			checkBoxListener({menuItemId, checked}) {
				if (CMIID_CHECKBOX != menuItemId) { // assert
					console.error(`${logPrefix}: checkbox: context menu item id '${menuItemId}' != '${CMIID_CHECKBOX}'`);
				}

				currentValue = null;
				if (!checked) {
					interceptor.off();
					return;
				}

				if (!currentMenu.has(menuItemId)) {
					console.error(`${logPrefix}: checkbox: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
					return;
				}

				currentValue = currentMenu.get(menuItemId);
				interceptor.on();
			},

			arrayListener({menuItemId}) {
				currentValue = null;
				if (menuItemId === CMIID_DEFAULT) {
					interceptor.off();
					return;
				}

				if (!currentMenu.has(menuItemId)) {
					console.error(`${logPrefix}: array: unknown context menu item id '${menuItemId}'`);
					interceptor.off();
					return;
				}

				currentValue = currentMenu.get(menuItemId);
				interceptor.on();
			},

			setListener(newListener) {
				if (newListener === this.listener) {
					return;
				}
				if (this.listener != null) {
					chrome.contextMenus.onClicked.removeListener(this.listener);
				}
				if (newListener != null) {
					this.listener = newListener;
					chrome.contextMenus.onClicked.addListener(this.listener);
				} else {
					console.error(`${logPrefix}: setListener(null)`);
					interceptor.off();
				}
			},

			createConfig(isDefault) {
				const prefix = isDefault ? '(!) ' : '';
				chrome.contextMenus.create({
					title: prefix + chrome.i18n.getMessage("contextMenuOptionsItem"),
					id: CMIID_OPTIONS,
					contexts
				});

				interceptor.off();
				this.setListener(this.configListener);
			},

			createCheckBox({checked, title}) {
				// Suppress "16" and "32" icons by empty string in manifest.json,
				// otherwise the icon will be overlapped with checkbox.
				const id = CMIID_CHECKBOX;
				const result = chrome.contextMenus.create({
					title: `Alt Tong: ${title}`,
					id,
					contexts,
					type: "checkbox",
					checked
				}, () => this.checkBoxListener({ menuItemId: id, checked }));

				this.setListener(this.checkBoxListener);
				return result;
			},

			createRadioItem({id, checked, title}) {
				return chrome.contextMenus.create(
					{
						title,
						id,
						contexts,
						type: "radio",
						checked
					},
					() => {
						if (checked) {
							this.checkBoxListener({ menuItemId: id, checked });
						}
					}
				);
			},

			createDefaultItem(checked) {
				const result = this.createRadioItem({
					id: CMIID_DEFAULT,
					checked,
					title: chrome.i18n.getMessage("menuDefault")
				});

				this.setListener(this.arrayListener);
				return result;
			}
		};
	})(interceptor);

	function updateContextMenu(newItems, defaultLangs) {
		let removed = browser.contextMenus.removeAll();
		currentMenu.clear();

		if (newItems == null || !(newItems.length > 0)) {
			const isDefault = (newItems != null
					&& newItems.length === 1 && newItems[0].value === defaultLangs);
			removed.then(() => contextMenus.createConfig(isDefault));
			return false;
		}

		const nonDefaultChecked = (currentValue != null) && (
			newItems.length === 1 || newItems.some(item => currentValue === item.value)
		);

		if (newItems.length === 1) {
			removed.then(() => {
				const item = newItems[0];
				currentValue = item.value;
				const id = contextMenus.createCheckBox({
					title: item.title || item.value,
					checked: nonDefaultChecked
				});
				currentMenu.set(id, item.value);
			});
		} else {
			// Not available trough options.html
			// May be tested from debugger
			// AltTong.configure({optionList: [ {value: "fr", title: "Fr"}, {value: "de", title: "De"} ] })

			// FIXME If newItems is string
			removed.then(() => {
				contextMenus.createDefaultItem(!nonDefaultChecked);
				newItems.forEach((item, index) => {
					if (item.value == null || item.value === '') {
						console.error(`${logPrefix}: empty value in updateContextMenu`);;
						return;
					}
					const id = "at-i" + (index + 1);
					const checked = nonDefaultChecked && item.value === currentValue;
					currentMenu.set(id, item.value);
					contextMenus.createRadioItem({
						title: item.title || item.value, // FIXME til , or ;
						id,
						checked
					});
				});
			});
		}
		return true;
	}

	const OPT_STORAGE_OPTION_LIST = "optionList";
	function getOptions() {
		return browser.storage.local.get(OPT_STORAGE_OPTION_LIST);
	}
	function saveOptions(options) {
		return browser.storage.local.set({
			[OPT_STORAGE_OPTION_LIST]: options[OPT_STORAGE_OPTION_LIST]
		});
	}
	function configure(options) {
		if (options != null) {
			return saveOptions(options)
				.then(() => doConfigure(options));
		} else {
			return getOptions().then(options => configure(options));
		}
	}
	function doConfigure(options) {
		return getAcceptLanguages()
			.then(
				langs => updateContextMenu(options.optionList, langs),
				() => updateContextMenu(options.optionList, null)
			).then(null, (e) => { console.error('Alt-Tong: doConfigure', e); });
	}

	function getAcceptLanguages() {
		// browser.i18n.getAcceptLanguages() returns array of language codes,
		// not a header content, so sniff for the actual value.
		return new Promise((resolve, reject) => {
			try {
				const testURL = 'http://localhost/';
				function extractAcceptLanguages({requestHeaders}) {
					var isFakeRequest = false;
					var acceptLanguage;
					for (let header of requestHeaders) {
						if (header.name.toLowerCase() === 'accept-language') {
							acceptLanguage = header.value;
						} else if (header.name.toLowerCase() === 'x-alttong-sniff-header') {
							isFakeRequest = true;
						}
						if (isFakeRequest && acceptLanguage != null) {
							break;
						}
					}
					if (isFakeRequest) {
						chrome.webRequest.onBeforeSendHeaders.removeListener(extractAcceptLanguages);
						resolve(acceptLanguage);
						return { cancel: true, requestHeaders };
					} else {
						return { requestHeaders };
					}
				}
				var fakeRequest = new XMLHttpRequest();
				fakeRequest.addEventListener('load', () => reject(new Error('Failed to catch test XHR')));
				fakeRequest.open('HEAD', testURL);
				fakeRequest.setRequestHeader('X-AltTong-Sniff-Header', 'Accept-Languages');

				const origReject = reject;
				reject = reason => {
					console.error(reason);
					chrome.webRequest.onBeforeSendHeaders.removeListener(extractAcceptLanguages);
					origReject(reason);
				};
				chrome.webRequest.onBeforeSendHeaders.addListener(
					extractAcceptLanguages,
					{ urls: [ testURL ] },
					[ 'blocking', 'requestHeaders' ]
				);
				// For some reason synchronous call of send() results in not caught request.
				// Zero timeout does not work during first loading of this extension.
				// Reload extension works even with zero timeout.
				setTimeout(() => fakeRequest.send(), 20);
			} catch (e) {
				reject(e);
			}
		});
	}

	return { configure, getOptions, getAcceptLanguages, OPT_STORAGE_OPTION_LIST };
})();

AltTong.configure();
<|endoftext|>


<commit_before>define(["./customer.js",
        "./map.js"], function (customer, map) {

    function OnDataChange (bezl) {
        // Populate the 'customers' array if we got CustomerList back
        if (bezl.data.CustList) {
            bezl.vars.customers = [];
            for (var i = 0; i < bezl.data.CustList.length; i++) {
                bezl.vars.customers.push({ selected: false,
                                            key: bezl.data.CustList[i].CustNum,
                                            display: bezl.data.CustList[i].Name,
                                            distance: null,
                                            streetAddress: bezl.data.CustList[i].Address,
                                            title: bezl.data.CustList[i].Name,
                                            custNum: bezl.data.CustList[i].CustNum,
                                            shipToNum: bezl.data.CustList[i].ShipToNum,
                                            data: bezl.data.CustList[i]
                                            });
            }

            // Configure the typeahead controls for the customer and customer search.  For full documentation of
            // available settings here see http://www.runningcoder.org/jquerytypeahead/documentation/
            $('.js-typeahead-customers').typeahead({
                order: "asc",
                maxItem: 8,
                source: {
                    data: function() { return bezl.vars.customers; }
                },
                callback: {
                    onClick: function (node, a, item, event) {
                        customer.select(bezl, item.key);
                    }
                }
            });

            bezl.vars.loading.customerList = false;

            // Now loop through the results and plot each
            for (var i = 0; i < bezl.data.CustList.length; i++) {
                if (bezl.data.CustList[i].Address.length > 3) {

                    // Test to see whether we already saved the geocode.  If not, use the API to calculate it and save it
                    if (bezl.data.CustList[i].Geocode_Location == "" ||  bezl.data.CustList[i].Geocode_Location == null) {
                        map.geocodeAddress(
                            bezl,
                            {
                                streetAddress: bezl.data.CustList[i].Address,
                                title: bezl.data.CustList[i].Name,
                                custNum: bezl.data.CustList[i].CustNum,
                                shipToNum: bezl.data.CustList[i].ShipToNum,
                                data: bezl.data.CustList[i]
                            }
                        );
                    } else {
                        var marker = new bezl.vars.client.Marker({
                            position: { lat: + parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[0].split(':')[1]), lng: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[1].split(':')[1]) },
                            map: bezl.vars.map,
                            title: bezl.data.CustList[i].Name,
                            data: bezl.data.CustList[i],
                            lat: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[0].split(':')[1]),
                            lng: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[1].split(':')[1])
                        });

                        // Add a click handler
                        marker.addListener('click', function() {
                            customer.select(bezl, this.data.CustNum);
                        });

                        bezl.vars.markers[bezl.data.CustList[i].CustNum] = marker;
                    }
                }
            };

            // Calculate distances
            map.calculateDistances(bezl);

            // Clean up CustList data subscription as we no longer need it
            bezl.dataService.remove('CustList');
            bezl.data.CustList = null;
        }
    }

    return {
        onDataChange: OnDataChange
    }
});<commit_msg>undefined bug<commit_after>define([], function () {

    function OnDataChange (bezl) {
        // Populate the 'customers' array if we got CustomerList back
        if (bezl.data.CustList) {
            bezl.vars.customers = [];
            for (var i = 0; i < bezl.data.CustList.length; i++) {
                bezl.vars.customers.push({ selected: false,
                                            key: bezl.data.CustList[i].CustNum,
                                            display: bezl.data.CustList[i].Name,
                                            distance: null,
                                            streetAddress: bezl.data.CustList[i].Address,
                                            title: bezl.data.CustList[i].Name,
                                            custNum: bezl.data.CustList[i].CustNum,
                                            shipToNum: bezl.data.CustList[i].ShipToNum,
                                            data: bezl.data.CustList[i]
                                            });
            }

            // Configure the typeahead controls for the customer and customer search.  For full documentation of
            // available settings here see http://www.runningcoder.org/jquerytypeahead/documentation/
            $('.js-typeahead-customers').typeahead({
                order: "asc",
                maxItem: 8,
                source: {
                    data: function() { return bezl.vars.customers; }
                },
                callback: {
                    onClick: function (node, a, item, event) {
                        bezl.vars.customerFile.select(bezl, item.key);
                    }
                }
            });

            bezl.vars.loading.customerList = false;

            // Now loop through the results and plot each
            for (var i = 0; i < bezl.data.CustList.length; i++) {
                if (bezl.data.CustList[i].Address.length > 3) {

                    // Test to see whether we already saved the geocode.  If not, use the API to calculate it and save it
                    if (bezl.data.CustList[i].Geocode_Location == "" ||  bezl.data.CustList[i].Geocode_Location == null) {
                        bezl.vars.mapFile.geocodeAddress(
                            bezl,
                            {
                                streetAddress: bezl.data.CustList[i].Address,
                                title: bezl.data.CustList[i].Name,
                                custNum: bezl.data.CustList[i].CustNum,
                                shipToNum: bezl.data.CustList[i].ShipToNum,
                                data: bezl.data.CustList[i]
                            }
                        );
                    } else {
                        var marker = new bezl.vars.client.Marker({
                            position: { lat: + parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[0].split(':')[1]), lng: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[1].split(':')[1]) },
                            map: bezl.vars.map,
                            title: bezl.data.CustList[i].Name,
                            data: bezl.data.CustList[i],
                            lat: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[0].split(':')[1]),
                            lng: parseFloat(bezl.data.CustList[i].Geocode_Location.split(',')[1].split(':')[1])
                        });

                        // Add a click handler
                        marker.addListener('click', function() {
                            bezl.vars.customerFile.select(bezl, this.data.CustNum);
                        });

                        bezl.vars.markers[bezl.data.CustList[i].CustNum] = marker;
                    }
                }
            };

            // Calculate distances
            bezl.vars.mapFile.calculateDistances(bezl);

            // Clean up CustList data subscription as we no longer need it
            bezl.dataService.remove('CustList');
            bezl.data.CustList = null;
        }
    }

    return {
        onDataChange: OnDataChange
    }
});<|endoftext|>


<commit_before>"use strict";

/*
A place to draw on with vectors.
 */

(function() {
  var Canvas;

  Canvas = (function() {
    function Canvas(canvas_element) {
      this.el = canvas_element;
      this.ctx = canvas_element.getContext("2d");
      this.o = Vector["null"];
      this.s = 1;
    }
<<<<<<< HEAD

    Canvas.prototype.origin = function(o) {
      this.o = Vector.fromArray(o);
      return this;
    };

    Canvas.prototype.scale = function(x) {
      this.s = x;
      return this;
    };

    Canvas.prototype.linecolor = function(color) {
      this.ctx.strokeStyle = color;
      return this;
    };

    Canvas.prototype.linewidth = function(width) {
      this.ctx.lineWidth = width * this.s;
      return this;
    };

    Canvas.prototype._convert = function(p) {
      p = (p.x == null) || (p.y == null) ? Vector.fromArray(p) : p;
      return this.o.plus(p.multiply(this.s));
    };

    Canvas.prototype.circle = function(p, r) {
      var p_;
      this.ctx.beginPath();
      p_ = this._convert(p);
      this.ctx.arc(p_.x, p_.y, r * this.s, 0, 2 * Math.PI);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.line = function(from, to) {
      var from_, to_;
      this.ctx.beginPath();
      from_ = this._convert(from);
      to_ = from_.plus(to.multiply(this.s));
      this.ctx.moveTo(from_.x, from_.y);
      this.ctx.lineTo(to_.x, to_.y);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.clear = function(color) {
      if (color == null) {
        color = 'rgba(255,255,255,1)';
      }
      this.ctx.fillStyle = color;
      return this.ctx.fillRect(0, 0, this.el.width, this.el.height);
    };

    return Canvas;

  })();

=======

    Canvas.prototype.origin = function(o) {
      this.o = Vector.fromArray(o);
      return this;
    };

    Canvas.prototype.scale = function(x) {
      this.s = x;
      return this;
    };

    Canvas.prototype.linecolor = function(color) {
      this.ctx.strokeStyle = color;
      return this;
    };

    Canvas.prototype.linewidth = function(width) {
      this.ctx.lineWidth = width;
      return this;
    };

    Canvas.prototype._convert = function(p) {
      p = (p.x == null) || (p.y == null) ? Vector.fromArray(p) : p;
      return this.o.plus(p.multiply(this.s));
    };

    Canvas.prototype.circle = function(p, r) {
      var p_;
      this.ctx.beginPath();
      p_ = this._convert(p);
      this.ctx.arc(p_.x, p_.y, r * this.s, 0, 2 * Math.PI);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.line = function(from, to) {
      var from_, to_;
      this.ctx.beginPath();
      from_ = this._convert(from);
      to_ = from_.plus(to.multiply(this.s));
      this.ctx.moveTo(from_.x, from_.y);
      this.ctx.lineTo(to_.x, to_.y);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.clear = function(color) {
      if (color == null) {
        color = 'rgba(255,255,255,1)';
      }
      this.ctx.fillStyle = color;
      return this.ctx.fillRect(0, 0, this.el.width, this.el.height);
    };

    return Canvas;

  })();

>>>>>>> Better-universe
  window.Canvas = Canvas;

}).call(this);

/*
A planet, floating around in the universe.
Pulled by his friends and pushed by love.
 */

(function() {
<<<<<<< HEAD
  var G, Planet;

  G = 10e4;

  Planet = (function() {
    function Planet(mass, position, speed, timespeed) {
=======
  var Planet;

  Planet = (function() {
    function Planet(mass, position, speed) {
>>>>>>> Better-universe
      if (position instanceof Array) {
        position = Vector.fromArray(position);
      }
      if (speed instanceof Array) {
        speed = Vector.fromArray(speed);
      }
      if (position.x == null) {
        throw new TypeError('Position should be a Vector');
      }
      if (speed.x == null) {
        throw new TypeError('Speed should be a Vector');
      }
<<<<<<< HEAD
      this.timespeed = timespeed;
      this.timespeed2 = timespeed * timespeed;
      this.G = this.timespeed2 / G;
      this.mass = mass;
      this.p = position;
      this.s = speed.multiply(this.timespeed);
=======
      this.mass = mass;
      this.p = position;
      this.s = speed;
>>>>>>> Better-universe
      this.a = Vector["null"];
      this.size = Math.max(10, Math.log(mass) * 5 + 10);
    }

    Planet.prototype.draw = function(canvas) {
      var scale;
<<<<<<< HEAD
      canvas.linewidth('2').linecolor('rgba(0,0,0,1)').circle(this.p, this.size).circle(this.p, 5);
=======
      canvas.linewidth('2').linecolor('rgba(0,0,0,1)').circle(this.p, this.size).circle(this.p, 2 / canvas.s);
>>>>>>> Better-universe
      canvas.linewidth('3');
      scale = 50 / this.timespeed;
      canvas.linecolor('rgba(255,0,0,1)').line(this.p, this.s.multiply(scale));
      scale = 1000 / this.timespeed2;
      return canvas.linecolor('rgba(0,255,0,1)').line(this.p, this.a.multiply(scale));
    };

<<<<<<< HEAD
    Planet.prototype.move = function() {
      return this.p = this.p.plus(this.s);
    };

    Planet.prototype.accelerate = function(entities) {
=======
    Planet.prototype.move = function(timespeed) {
      return this.p = this.p.plus(this.s.multiply(timespeed));
    };

    Planet.prototype.accelerate = function(entities, timespeed, G) {
>>>>>>> Better-universe
      var a;
      a = fast.map(entities, (function(_this) {
        return function(entitie) {
          var dp, force, r2;
          if (entitie === _this || entitie.mass === 0) {
            return Vector["null"];
          }
          dp = entitie.p.minus(_this.p);
          r2 = dp.size2();
          if (r2 === 0) {
            return Vector["null"];
          }
          force = entitie.mass / (r2 * Math.sqrt(r2));
          return dp.multiply(force);
        };
      })(this));
      a = fast.reduce(a, function(p, n) {
        return p.plus(n);
      }, Vector["null"]);
<<<<<<< HEAD
      this.a = a.multiply(this.G);
=======
      this.a = a.multiply(timespeed * G);
>>>>>>> Better-universe
      return this.s = this.s.plus(this.a);
    };

    return Planet;

  })();

  window.Planet = Planet;

}).call(this);

/*
Represents a universe with planets floating around in it..
Floaty float.. floaty float...
 */

(function() {
  var Universe;

  Universe = (function() {
<<<<<<< HEAD
    function Universe(options) {
      this.timespeed = options.timespeed;
      if (this.imespeed == null) {
        this.imespeed = 1;
      }
      this.planets = [];
      this.origin = Vector["null"];
    }

    Universe.prototype.addPlanet = function(mass, position, speed) {
      var planet;
      planet = new Planet(mass, position, speed, this.timespeed);
      return this.planets.push(planet);
    };

    Universe.prototype.run = function(t) {
      var i, planet, _i, _j, _k, _len, _len1, _ref, _ref1;
      for (i = _i = 0; 0 <= t ? _i < t : _i > t; i = 0 <= t ? ++_i : --_i) {
        _ref = this.planets;
        for (_j = 0, _len = _ref.length; _j < _len; _j++) {
          planet = _ref[_j];
          planet.accelerate(this.planets);
        }
        _ref1 = this.planets;
        for (_k = 0, _len1 = _ref1.length; _k < _len1; _k++) {
          planet = _ref1[_k];
          planet.move();
        }
      }
    };

    Universe.prototype.draw = function(canvas) {
      var planet, _i, _len, _ref, _results;
      _ref = this.planets;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        planet = _ref[_i];
        _results.push(planet.draw(canvas));
      }
      return _results;
    };

    Universe.prototype.loop = function(canvas, speed) {
      var history;
      if (speed == null) {
        speed = 2;
      }
      history = performance.now();
      return setInterval((function(_this) {
        return function() {
          var seconds;
          seconds = performance.now() - history;
          history = performance.now();
          seconds = Math.min(seconds, 20);
          canvas.clear();
          _this.run(seconds * speed);
          return _this.draw(canvas);
        };
      })(this), 1);
    };

    return Universe;

  })();

  window.Universe = Universe;

=======
    Universe.SECOND = 1;

    Universe.DAY = 86400;

    Universe.YEAR = 3.15569e7;

    Universe.KG = 1;

    Universe.KG24 = 1e24;

    Universe.M = 1;

    Universe.KM = 1e3;

    Universe.G = 6.67384e-11;

    function Universe(opts) {
      if (opts == null) {
        opts = {};
      }
      this.opts = {
        speed: opts.speed || 1,
        accuracy: opts.accuracy || 1,
        scale: opts.scale || 1
      };
      this.opts.speed = this.opts.speed / this.opts.accuracy;
      this.planets = [];
      this.t = 0;
    }

    Universe.prototype.addPlanet = function(mass, position, speed) {
      var planet, scale, scale3;
      scale = this.opts.scale;
      scale3 = scale * scale * scale;
      if (position instanceof Array) {
        position = Vector.fromArray(position);
      }
      if (speed instanceof Array) {
        speed = Vector.fromArray(speed);
      }
      if (position.x == null) {
        throw new TypeError('Position should be a Vector');
      }
      if (speed.x == null) {
        throw new TypeError('Speed should be a Vector');
      }
      planet = new Planet(mass * scale3, position.multiply(scale), speed.multiply(scale), this.opts);
      return this.planets.push(planet);
    };

    Universe.prototype.run = function(t) {
      var i, planet, planets, speed, _i, _j, _k, _len, _len1;
      speed = this.opts.speed;
      planets = this.planets;
      for (i = _i = 0; 0 <= t ? _i < t : _i > t; i = 0 <= t ? ++_i : --_i) {
        for (_j = 0, _len = planets.length; _j < _len; _j++) {
          planet = planets[_j];
          planet.accelerate(planets, speed, Universe.G);
        }
        for (_k = 0, _len1 = planets.length; _k < _len1; _k++) {
          planet = planets[_k];
          planet.move(speed);
        }
      }
    };

    Universe.prototype.draw = function(canvas) {
      var planet, _i, _len, _ref, _results;
      _ref = this.planets;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        planet = _ref[_i];
        _results.push(planet.draw(canvas));
      }
      return _results;
    };

    Universe.prototype.loop = function(canvas) {
      var accuracy, history;
      history = performance.now();
      accuracy = this.opts.accuracy;
      return setInterval((function(_this) {
        return function() {
          var seconds;
          seconds = performance.now() - history;
          history = performance.now();
          seconds = Math.min(seconds, 20);
          canvas.clear();
          _this.run(seconds * accuracy);
          return _this.draw(canvas);
        };
      })(this), 1);
    };

    return Universe;

  })();

  window.Universe = Universe;

>>>>>>> Better-universe
}).call(this);

/*
Represents a Vector in 2D space
---
All methods on a vector are pure, a vector is immutable.
 */
<<<<<<< HEAD

(function() {
  var Vector, vector;

=======

(function() {
  var Vector, vector;

>>>>>>> Better-universe
  vector = function(x, y) {
    return new Vector(x, y);
  };

  Vector = (function() {
    function Vector(x, y) {
      this.x = x;
      this.y = y;
    }

    Vector.fromArray = function(array) {
      return new Vector(array[0], array[1]);
    };

    Vector["null"] = Vector.fromArray([0, 0]);

    Vector.prototype.toArray = function() {
      return [this.x, this.y];
    };

    Vector.prototype.map = function(fn) {
      return new Vector(fn(this.x), fn(this.y));
    };

    Vector.prototype.zipWith = function(v, fn) {
      if ((v.x == null) || (v.y == null)) {
        return new Vector(fn(this.x, v), fn(this.y, v));
      } else {
        return new Vector(fn(this.x, v.x), fn(this.y, v.y));
      }
    };

    Vector.prototype.plus = function(input) {
      return this.zipWith(input, function(x, y) {
        return x + y;
      });
    };

    Vector.prototype.minus = function(input) {
      return this.zipWith(input, function(x, y) {
        return x - y;
      });
    };

    Vector.prototype.multiply = function(input) {
      return this.zipWith(input, function(x, y) {
        return x * y;
      });
    };

    Vector.prototype.divide = function(input) {
      if (input instanceof Vector) {
        return this.zipWith(input, function(x, y) {
          return x / y;
        });
      } else {
        return this.multiply(1 / input);
      }
    };

    Vector.prototype.size2 = function() {
      return this.x * this.x + this.y * this.y;
    };

    Vector.prototype.size = function() {
      return Math.sqrt(this.size2());
    };

    Vector.prototype.norm = function() {
      return this.divide(this.size());
    };

    return Vector;

  })();

  window.Vector = Vector;

  window.vector = vector;

}).call(this);
<commit_msg>Build was screwed up after branch merge :p<commit_after>"use strict";

/*
A place to draw on with vectors.
 */

(function() {
  var Canvas;

  Canvas = (function() {
    function Canvas(canvas_element) {
      this.el = canvas_element;
      this.ctx = canvas_element.getContext("2d");
      this.o = Vector["null"];
      this.s = 1;
    }

    Canvas.prototype.origin = function(o) {
      this.o = Vector.fromArray(o);
      return this;
    };

    Canvas.prototype.scale = function(x) {
      this.s = x;
      return this;
    };

    Canvas.prototype.linecolor = function(color) {
      this.ctx.strokeStyle = color;
      return this;
    };

    Canvas.prototype.linewidth = function(width) {
      this.ctx.lineWidth = width;
      return this;
    };

    Canvas.prototype._convert = function(p) {
      p = (p.x == null) || (p.y == null) ? Vector.fromArray(p) : p;
      return this.o.plus(p.multiply(this.s));
    };

    Canvas.prototype.circle = function(p, r) {
      var p_;
      this.ctx.beginPath();
      p_ = this._convert(p);
      this.ctx.arc(p_.x, p_.y, r * this.s, 0, 2 * Math.PI);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.line = function(from, to) {
      var from_, to_;
      this.ctx.beginPath();
      from_ = this._convert(from);
      to_ = from_.plus(to.multiply(this.s));
      this.ctx.moveTo(from_.x, from_.y);
      this.ctx.lineTo(to_.x, to_.y);
      this.ctx.stroke();
      return this;
    };

    Canvas.prototype.clear = function(color) {
      if (color == null) {
        color = 'rgba(255,255,255,1)';
      }
      this.ctx.fillStyle = color;
      return this.ctx.fillRect(0, 0, this.el.width, this.el.height);
    };

    return Canvas;

  })();

  window.Canvas = Canvas;

}).call(this);

/*
A planet, floating around in the universe.
Pulled by his friends and pushed by love.
 */

(function() {
  var Planet;

  Planet = (function() {
    function Planet(mass, position, speed) {
      if (position instanceof Array) {
        position = Vector.fromArray(position);
      }
      if (speed instanceof Array) {
        speed = Vector.fromArray(speed);
      }
      if (position.x == null) {
        throw new TypeError('Position should be a Vector');
      }
      if (speed.x == null) {
        throw new TypeError('Speed should be a Vector');
      }
      this.mass = mass;
      this.p = position;
      this.s = speed;
      this.a = Vector["null"];
      this.size = Math.max(10, Math.log(mass) * 5 + 10);
    }

    Planet.prototype.draw = function(canvas) {
      var scale;
      canvas.linewidth('2').linecolor('rgba(0,0,0,1)').circle(this.p, this.size).circle(this.p, 2 / canvas.s);
      canvas.linewidth('3');
      scale = 50 / this.timespeed;
      canvas.linecolor('rgba(255,0,0,1)').line(this.p, this.s.multiply(scale));
      scale = 1000 / this.timespeed2;
      return canvas.linecolor('rgba(0,255,0,1)').line(this.p, this.a.multiply(scale));
    };

    Planet.prototype.move = function(timespeed) {
      return this.p = this.p.plus(this.s.multiply(timespeed));
    };

    Planet.prototype.accelerate = function(entities, timespeed, G) {
      var a;
      a = fast.map(entities, (function(_this) {
        return function(entitie) {
          var dp, force, r2;
          if (entitie === _this || entitie.mass === 0) {
            return Vector["null"];
          }
          dp = entitie.p.minus(_this.p);
          r2 = dp.size2();
          if (r2 === 0) {
            return Vector["null"];
          }
          force = entitie.mass / (r2 * Math.sqrt(r2));
          return dp.multiply(force);
        };
      })(this));
      a = fast.reduce(a, function(p, n) {
        return p.plus(n);
      }, Vector["null"]);
      this.a = a.multiply(timespeed * G);
      return this.s = this.s.plus(this.a);
    };

    return Planet;

  })();

  window.Planet = Planet;

}).call(this);

/*
Represents a universe with planets floating around in it..
Floaty float.. floaty float...
 */

(function() {
  var Universe;

  Universe = (function() {
    Universe.SECOND = 1;

    Universe.DAY = 86400;

    Universe.YEAR = 3.15569e7;

    Universe.KG = 1;

    Universe.KG24 = 1e24;

    Universe.M = 1;

    Universe.KM = 1e3;

    Universe.G = 6.67384e-11;

    function Universe(opts) {
      if (opts == null) {
        opts = {};
      }
      this.opts = {
        speed: opts.speed || 1,
        accuracy: opts.accuracy || 1,
        scale: opts.scale || 1
      };
      this.opts.speed = this.opts.speed / this.opts.accuracy;
      this.planets = [];
      this.t = 0;
    }

    Universe.prototype.addPlanet = function(mass, position, speed) {
      var planet, scale, scale3;
      scale = this.opts.scale;
      scale3 = scale * scale * scale;
      if (position instanceof Array) {
        position = Vector.fromArray(position);
      }
      if (speed instanceof Array) {
        speed = Vector.fromArray(speed);
      }
      if (position.x == null) {
        throw new TypeError('Position should be a Vector');
      }
      if (speed.x == null) {
        throw new TypeError('Speed should be a Vector');
      }
      planet = new Planet(mass * scale3, position.multiply(scale), speed.multiply(scale), this.opts);
      return this.planets.push(planet);
    };

    Universe.prototype.run = function(t) {
      var i, planet, planets, speed, _i, _j, _k, _len, _len1;
      speed = this.opts.speed;
      planets = this.planets;
      for (i = _i = 0; 0 <= t ? _i < t : _i > t; i = 0 <= t ? ++_i : --_i) {
        for (_j = 0, _len = planets.length; _j < _len; _j++) {
          planet = planets[_j];
          planet.accelerate(planets, speed, Universe.G);
        }
        for (_k = 0, _len1 = planets.length; _k < _len1; _k++) {
          planet = planets[_k];
          planet.move(speed);
        }
      }
    };

    Universe.prototype.draw = function(canvas) {
      var planet, _i, _len, _ref, _results;
      _ref = this.planets;
      _results = [];
      for (_i = 0, _len = _ref.length; _i < _len; _i++) {
        planet = _ref[_i];
        _results.push(planet.draw(canvas));
      }
      return _results;
    };

    Universe.prototype.loop = function(canvas) {
      var accuracy, history;
      history = performance.now();
      accuracy = this.opts.accuracy;
      return setInterval((function(_this) {
        return function() {
          var seconds;
          seconds = performance.now() - history;
          history = performance.now();
          seconds = Math.min(seconds, 20);
          canvas.clear();
          _this.run(seconds * accuracy);
          return _this.draw(canvas);
        };
      })(this), 1);
    };

    return Universe;

  })();

  window.Universe = Universe;

}).call(this);

/*
Represents a Vector in 2D space
---
All methods on a vector are pure, a vector is immutable.
 */

(function() {
  var Vector, vector;

  vector = function(x, y) {
    return new Vector(x, y);
  };

  Vector = (function() {
    function Vector(x, y) {
      this.x = x;
      this.y = y;
    }

    Vector.fromArray = function(array) {
      return new Vector(array[0], array[1]);
    };

    Vector["null"] = Vector.fromArray([0, 0]);

    Vector.prototype.toArray = function() {
      return [this.x, this.y];
    };

    Vector.prototype.map = function(fn) {
      return new Vector(fn(this.x), fn(this.y));
    };

    Vector.prototype.zipWith = function(v, fn) {
      if ((v.x == null) || (v.y == null)) {
        return new Vector(fn(this.x, v), fn(this.y, v));
      } else {
        return new Vector(fn(this.x, v.x), fn(this.y, v.y));
      }
    };

    Vector.prototype.plus = function(input) {
      return this.zipWith(input, function(x, y) {
        return x + y;
      });
    };

    Vector.prototype.minus = function(input) {
      return this.zipWith(input, function(x, y) {
        return x - y;
      });
    };

    Vector.prototype.multiply = function(input) {
      return this.zipWith(input, function(x, y) {
        return x * y;
      });
    };

    Vector.prototype.divide = function(input) {
      if (input instanceof Vector) {
        return this.zipWith(input, function(x, y) {
          return x / y;
        });
      } else {
        return this.multiply(1 / input);
      }
    };

    Vector.prototype.size2 = function() {
      return this.x * this.x + this.y * this.y;
    };

    Vector.prototype.size = function() {
      return Math.sqrt(this.size2());
    };

    Vector.prototype.norm = function() {
      return this.divide(this.size());
    };

    return Vector;

  })();

  window.Vector = Vector;

  window.vector = vector;

}).call(this);
<|endoftext|>


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

    var app = angular.module('activities.controllers', ['ngSanitize']);

    app.controller('PHPCtrl', ['$scope', '$sce', 'Progress',
        function ($scope, $sce, Progress) {

            $scope.disableResultTab = true;
            $scope.cm_refresh = 0;
            $scope.iframeRefresh = 0;

            $scope.refresh  = function() {
                $scope.cm_refresh += 1;
            };

            $scope.answer.$promise.finally(function() {
                if (!$scope.answer.id) {
                    $scope.answer.given = $scope.currentActivity.data;
                }
                $scope.answer.given[0].active = true;
                $scope.refresh();
            });

             $scope.sendPhpAnswer = function() {
                 $scope.answer.activity = $scope.currentActivity.id;
                 $scope.answer.$update({activityId: $scope.answer.activity}, function () {
                     $scope.disableResultTab = false;
                     $scope.resultUrl = $sce.trustAsResourceUrl('http://php' + $scope.answer.user_id + '.timtec.com.br/');
                     $scope.iframeRefresh += 1;
                 }).then(function(d){
//                    ga('send', 'event', 'activity', 'result', '', d.correct);
                     return Progress.getProgressByUnitId($scope.currentUnit.id);
                 }).then(function(progress){
                     $scope.currentUnit.progress = progress;
                 });
//                ga('send', 'event', 'activity', 'submit');

            };

            $scope.codemirrorLoaded = function(cm){
                // FIXME refactor this.
                var pid = setInterval(function(){
                    if ($scope.cm_refresh < 20) {
                        $scope.refresh();
                    } else
                        clearInterval(pid);
                }, 500);
            };

            $scope.codemirrorConfig = {
                        lineNumbers:true,
                        theme:'monokai',
                        matchTags: {bothTags: true},
                        matchBrackets: true,
                        extraKeys: {'Ctrl-J': 'toMatchingTag',
                                    'Ctrl-Space': 'autocomplete'},
                        mode:'php',
                        onLoad : $scope.codemirrorLoaded
            };
        }
    ]);

    app.controller('RelationshipCtrl', ['$scope',
        function ($scope) {

            function compareNumbers(a, b) {
              return a - b;
            }

            $scope.$watch('currentActivity', function(currentActivity) {
                $scope.possibleAnswers = currentActivity.expected.slice(0);
                $scope.possibleAnswers.sort(compareNumbers);
            });

            $scope.possibleAnswers = $scope.currentActivity.expected.slice(0);
            $scope.possibleAnswers.sort(compareNumbers);
        }
    ]);

    app.controller('DiscussionActivityCtrl', [
      '$scope',
      '$sce',
      '$routeParams',
      'uiTinymceConfig',
      'Forum',
      'Topic',
      'Comment',
      'TopicLike',
      'CommentLike',
      'CommentFile',

      function ($scope, $sce, $routeParams, uiTinymceConfig, Forum, Topic, Comment, TopicLike, CommentLike, CommentFile) {
        $scope.activity_open = true;
        $scope.activity_expired = false;
        var now = Date.now();

        // Decide the current state of the activity
        if(now < $scope.currentActivity.data[0].start_date){
          // The Activity is not open yet
          $scope.activity_open = false;
        } else if(now > $scope.currentActivity.data[0].end_date){
          // The Activity is already expired
          $scope.activity_expired = true;
        }

        // Check if there is an answer to this activity
        $scope.answer.$promise.then(function() {
            // if there is, show the corresponding topic that holds this answer and its comments
            $scope.show_answer = true;
            $scope.topic = Topic.get({id: $scope.answer.given.topic});
            uiTinymceConfig.automatic_uploads = true;
        });

        // if there is no answer, show the text editor and prepare to save it
        // $scope.forums = Forum.query();
        $scope.show_answer = false;
        $scope.new_topic = new Topic();
        $scope.new_topic.forum = 14;
        $scope.save_answer = function() {
            $scope.sending = true;
            $scope.new_topic.title = 'Resposta experimental';
            $scope.new_topic.$save(function(topic){
                $scope.answer.given = {topic: topic.id};
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$save();
            });
        };

        // Load other students activities
        $scope.latest_activities = Topic.query({
            forum: 14,
            limit: 3,
            ordering: '-last_activity_at',
            }, function(){
                $scope.activities_loaded = true;
            }
        );

        $scope.save_comment = function(topic, parent_comment) {
            var new_comment = new Comment();
            var new_comment_files = [];
            new_comment.topic = topic.id;
            if (parent_comment) {
                new_comment.parent = parent_comment.id;
                new_comment.text = parent_comment.new_comment;
                new_comment_files = parent_comment.new_comment_files;
                parent_comment.comment_replies.unshift(new_comment);
            } else {
                new_comment.text = topic.new_comment;
                topic.show_comment_input = false;
                new_comment_files = topic.new_comment_files;
                topic.comments.unshift(new_comment);
            }
            new_comment.$save().then(function(comment) {
                angular.forEach(new_comment_files, function(comment_file) {
                    comment_file.comment = comment.id;
                    delete comment_file.file;
                    comment_file.$patch().then(function(comment_file_complete) {
                        comment.files.push(comment_file_complete);
                    });
                });
            });
        };

        $scope.comment_like = function(comment) {
            if (comment.user_like) {
                CommentLike.delete({id:comment.user_like});
                comment.user_like = 0;
                comment.count_likes -=1;
            } else {
                // Change this before promisse so the user sees the action take effect.
                comment.user_like = -1;

                CommentLike.save({comment:comment.id}, function(comment_like){
                    comment.user_like = comment_like.id;
                });
            }
        };

      }
    ]);
})(angular);
<commit_msg>Added support for files in discussion activities' comments<commit_after>(function(angular){
    'use strict';

    var app = angular.module('activities.controllers', ['ngSanitize']);

    app.controller('PHPCtrl', ['$scope', '$sce', 'Progress',
        function ($scope, $sce, Progress) {

            $scope.disableResultTab = true;
            $scope.cm_refresh = 0;
            $scope.iframeRefresh = 0;

            $scope.refresh  = function() {
                $scope.cm_refresh += 1;
            };

            $scope.answer.$promise.finally(function() {
                if (!$scope.answer.id) {
                    $scope.answer.given = $scope.currentActivity.data;
                }
                $scope.answer.given[0].active = true;
                $scope.refresh();
            });

             $scope.sendPhpAnswer = function() {
                 $scope.answer.activity = $scope.currentActivity.id;
                 $scope.answer.$update({activityId: $scope.answer.activity}, function () {
                     $scope.disableResultTab = false;
                     $scope.resultUrl = $sce.trustAsResourceUrl('http://php' + $scope.answer.user_id + '.timtec.com.br/');
                     $scope.iframeRefresh += 1;
                 }).then(function(d){
//                    ga('send', 'event', 'activity', 'result', '', d.correct);
                     return Progress.getProgressByUnitId($scope.currentUnit.id);
                 }).then(function(progress){
                     $scope.currentUnit.progress = progress;
                 });
//                ga('send', 'event', 'activity', 'submit');

            };

            $scope.codemirrorLoaded = function(cm){
                // FIXME refactor this.
                var pid = setInterval(function(){
                    if ($scope.cm_refresh < 20) {
                        $scope.refresh();
                    } else
                        clearInterval(pid);
                }, 500);
            };

            $scope.codemirrorConfig = {
                        lineNumbers:true,
                        theme:'monokai',
                        matchTags: {bothTags: true},
                        matchBrackets: true,
                        extraKeys: {'Ctrl-J': 'toMatchingTag',
                                    'Ctrl-Space': 'autocomplete'},
                        mode:'php',
                        onLoad : $scope.codemirrorLoaded
            };
        }
    ]);

    app.controller('RelationshipCtrl', ['$scope',
        function ($scope) {

            function compareNumbers(a, b) {
              return a - b;
            }

            $scope.$watch('currentActivity', function(currentActivity) {
                $scope.possibleAnswers = currentActivity.expected.slice(0);
                $scope.possibleAnswers.sort(compareNumbers);
            });

            $scope.possibleAnswers = $scope.currentActivity.expected.slice(0);
            $scope.possibleAnswers.sort(compareNumbers);
        }
    ]);

    app.controller('DiscussionActivityCtrl', [
      '$scope',
      '$sce',
      '$routeParams',
      'uiTinymceConfig',
      'Forum',
      'Topic',
      'Comment',
      'TopicLike',
      'CommentLike',
      'CommentFile',

      function ($scope, $sce, $routeParams, uiTinymceConfig, Forum, Topic, Comment, TopicLike, CommentLike, CommentFile) {
        $scope.activity_open = true;
        $scope.activity_expired = false;
        var now = Date.now();

        // Decide the current state of the activity
        if(now < $scope.currentActivity.data[0].start_date){
          // The Activity is not open yet
          $scope.activity_open = false;
        } else if(now > $scope.currentActivity.data[0].end_date){
          // The Activity is already expired
          $scope.activity_expired = true;
        }

        // Check if there is an answer to this activity
        $scope.answer.$promise.then(function() {
            // if there is, show the corresponding topic that holds this answer and its comments
            $scope.show_answer = true;
            $scope.topic = Topic.get({id: $scope.answer.given.topic});
            uiTinymceConfig.automatic_uploads = true;
        });

        // if there is no answer, show the text editor and prepare to save it
        // $scope.forums = Forum.query();
        $scope.show_answer = false;
        $scope.new_topic = new Topic();
        $scope.new_topic.forum = 14;
        $scope.save_answer = function() {
            $scope.sending = true;
            $scope.new_topic.title = 'Resposta experimental';
            $scope.new_topic.$save(function(topic){
                $scope.answer.given = {topic: topic.id};
                $scope.answer.activity = $scope.currentActivity.id;
                $scope.answer.$save();
            });
        };

        // Load other students activities
        $scope.latest_activities = Topic.query({
            forum: 14,
            limit: 3,
            ordering: '-last_activity_at',
            }, function(){
                $scope.activities_loaded = true;
            }
        );

        $scope.save_comment = function(topic, parent_comment) {
            var new_comment = new Comment();
            var new_comment_files = [];
            new_comment.topic = topic.id;
            if (parent_comment) {
                new_comment.parent = parent_comment.id;
                new_comment.text = parent_comment.new_comment;
                new_comment_files = parent_comment.new_comment_files;
                parent_comment.comment_replies.unshift(new_comment);
            } else {
                new_comment.text = topic.new_comment;
                topic.show_comment_input = false;
                new_comment_files = topic.new_comment_files;
                topic.comments.unshift(new_comment);
            }
            new_comment.$save().then(function(comment) {
                angular.forEach(new_comment_files, function(comment_file) {
                    comment_file.comment = comment.id;
                    delete comment_file.file;
                    comment_file.$patch().then(function(comment_file_complete) {
                        comment.files.push(comment_file_complete);
                    });
                });
            });
        };

        $scope.comment_like = function(comment) {
            if (comment.user_like) {
                CommentLike.delete({id:comment.user_like});
                comment.user_like = 0;
                comment.count_likes -=1;
            } else {
                // Change this before promisse so the user sees the action take effect.
                comment.user_like = -1;

                CommentLike.save({comment:comment.id}, function(comment_like){
                    comment.user_like = comment_like.id;
                });
                comment.count_likes +=1;
            }
        };

        // ng-file-upload
        $scope.uploadCommentFiles = function (file, topic) {

            if (file) {
                CommentFile.upload(file).then(function (response) {
                    var comment_file = new CommentFile(response.data);

                    if (topic.new_comment_files === undefined)
                        topic.new_comment_files = [];
                    topic.new_comment_files.push(comment_file);
                    return {location: comment_file.file};
                }, function (response) {
                    if (response.status > 0) {
                        $scope.errorMsg = response.status + ': ' + response.data;
                    }
                }, function (evt) {
                    // $scope.progress =
                    //     Math.min(100, parseInt(100.0 * evt.loaded / evt.total));
                });
            }
        };

      }
    ]);
})(angular);
<|endoftext|>


<commit_before>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems                */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

define(function(require) {
  /*
    DEPENDENCIES
   */

  var BaseDialog = require('utils/dialogs/dialog');
  var TemplateHTML = require('hbs!./migrate/html');
  var Sunstone = require('sunstone');
  var DatastoresTable = require('tabs/datastores-tab/datatable');
  var HostsTable = require('tabs/hosts-tab/datatable');
  var Notifier = require('utils/notifier');
  var Tips = require('utils/tips');
  var Locale = require('utils/locale');
  var OpenNebulaVM = require('opennebula/vm');

  /*
    CONSTANTS
   */

  var DIALOG_ID = require('./migrate/dialogId');
  var TAB_ID = require('../tabId')

  /*
    CONSTRUCTOR
   */

  function Dialog() {
    this.dialogId = DIALOG_ID;

    this.hostsTable = new HostsTable('migrate_vm', {'select': true});
    this.datastoresTable = new DatastoresTable('migrate_vm_ds', {
      'select': true,
      'selectOptions': {
        'filter_fn': function(ds) { return ds.TYPE == 1; } // Show system DS only
      }
    });

    BaseDialog.call(this);
  };

  Dialog.DIALOG_ID = DIALOG_ID;
  Dialog.prototype = Object.create(BaseDialog.prototype);
  Dialog.prototype.constructor = Dialog;
  Dialog.prototype.html = _html;
  Dialog.prototype.onShow = _onShow;
  Dialog.prototype.setup = _setup;
  Dialog.prototype.setLive = _setLive;

  return Dialog;

  /*
    FUNCTION DEFINITIONS
   */

  function _html() {
    return TemplateHTML({
      'dialogId': this.dialogId,
      'hostsTableHTML': this.hostsTable.dataTableHTML,
      'datastoresTableHTML': this.datastoresTable.dataTableHTML
    });
  }

  function _setup(context) {
    var that = this;

    that.hostsTable.initialize();
    that.datastoresTable.initialize();

    Tips.setup(context);

    $('#' + DIALOG_ID + 'Form', context).submit(function() {
      var extra_info = {};

      if ($("#selected_resource_id_migrate_vm", context).val()) {
          extra_info['host_id'] = $("#selected_resource_id_migrate_vm", context).val();
      } else {
          notifyError(Locale.tr("You have not selected a host"));
          return false;
      }

      extra_info['ds_id'] = $("#selected_resource_id_migrate_vm_ds", context).val() || -1
      extra_info['enforce'] = $("#enforce", context).is(":checked");

      $.each(Sunstone.getDataTable(TAB_ID).elements(), function(index, elem) {
        if (that.live) {
          Sunstone.runAction("VM.migrate_live_action", elem, extra_info);
        } else {
          Sunstone.runAction("VM.migrate_action", elem, extra_info);
        }
      });

      Sunstone.getDialog(DIALOG_ID).hide();
      Sunstone.getDialog(DIALOG_ID).reset();
      return false;
    });

    return false;
  }

  function _onShow(context) {
    this.datastoresTable.resetResourceTableSelect();
    this.hostsTable.resetResourceTableSelect();

    if (this.live) {
      $(".migrate_vm_ds_selection", context).hide();
    }

    $.each(Sunstone.getDataTable(TAB_ID).elements(), function() {
      var vm_id = "" + this;

      OpenNebulaVM.show({
        data : {
          id: vm_id
        },
        timeout: true,
        success: function (request, vm_json) {
          var element = vm_json.VM;
          var hostname = OpenNebulaVM.hostnameStr(element);

          $('.confirm-resources-header', context).append(
              '' +
              Locale.tr("VM") + ' ' + element.ID + ' '+ element.NAME +' ' +
              Locale.tr("is currently running on Host") +
              ' ' + hostname + '
'
          );
        }
      });
    });
    return false;
  }

  // @param [Boolean] live Set migrate live or migrate
  function _setLive(live) {
    this.live = live;
  }
});
<commit_msg>Bug #4726: Fix error message when a host is not selected on migrate<commit_after>/* -------------------------------------------------------------------------- */
/* Copyright 2002-2016, OpenNebula Project, OpenNebula Systems                */
/*                                                                            */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may    */
/* not use this file except in compliance with the License. You may obtain    */
/* a copy of the License at                                                   */
/*                                                                            */
/* http://www.apache.org/licenses/LICENSE-2.0                                 */
/*                                                                            */
/* Unless required by applicable law or agreed to in writing, software        */
/* distributed under the License is distributed on an "AS IS" BASIS,          */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/* See the License for the specific language governing permissions and        */
/* limitations under the License.                                             */
/* -------------------------------------------------------------------------- */

define(function(require) {
  /*
    DEPENDENCIES
   */

  var BaseDialog = require('utils/dialogs/dialog');
  var TemplateHTML = require('hbs!./migrate/html');
  var Sunstone = require('sunstone');
  var DatastoresTable = require('tabs/datastores-tab/datatable');
  var HostsTable = require('tabs/hosts-tab/datatable');
  var Notifier = require('utils/notifier');
  var Tips = require('utils/tips');
  var Locale = require('utils/locale');
  var OpenNebulaVM = require('opennebula/vm');

  /*
    CONSTANTS
   */

  var DIALOG_ID = require('./migrate/dialogId');
  var TAB_ID = require('../tabId')

  /*
    CONSTRUCTOR
   */

  function Dialog() {
    this.dialogId = DIALOG_ID;

    this.hostsTable = new HostsTable('migrate_vm', {'select': true});
    this.datastoresTable = new DatastoresTable('migrate_vm_ds', {
      'select': true,
      'selectOptions': {
        'filter_fn': function(ds) { return ds.TYPE == 1; } // Show system DS only
      }
    });

    BaseDialog.call(this);
  };

  Dialog.DIALOG_ID = DIALOG_ID;
  Dialog.prototype = Object.create(BaseDialog.prototype);
  Dialog.prototype.constructor = Dialog;
  Dialog.prototype.html = _html;
  Dialog.prototype.onShow = _onShow;
  Dialog.prototype.setup = _setup;
  Dialog.prototype.setLive = _setLive;

  return Dialog;

  /*
    FUNCTION DEFINITIONS
   */

  function _html() {
    return TemplateHTML({
      'dialogId': this.dialogId,
      'hostsTableHTML': this.hostsTable.dataTableHTML,
      'datastoresTableHTML': this.datastoresTable.dataTableHTML
    });
  }

  function _setup(context) {
    var that = this;

    that.hostsTable.initialize();
    that.datastoresTable.initialize();

    Tips.setup(context);

    $('#' + DIALOG_ID + 'Form', context).submit(function() {
      var extra_info = {};

      if ($("#selected_resource_id_migrate_vm", context).val()) {
          extra_info['host_id'] = $("#selected_resource_id_migrate_vm", context).val();
      } else {
          Notifier.notifyError(Locale.tr("You have not selected a host"));
          return false;
      }

      extra_info['ds_id'] = $("#selected_resource_id_migrate_vm_ds", context).val() || -1
      extra_info['enforce'] = $("#enforce", context).is(":checked");

      $.each(Sunstone.getDataTable(TAB_ID).elements(), function(index, elem) {
        if (that.live) {
          Sunstone.runAction("VM.migrate_live_action", elem, extra_info);
        } else {
          Sunstone.runAction("VM.migrate_action", elem, extra_info);
        }
      });

      Sunstone.getDialog(DIALOG_ID).hide();
      Sunstone.getDialog(DIALOG_ID).reset();
      return false;
    });

    return false;
  }

  function _onShow(context) {
    this.datastoresTable.resetResourceTableSelect();
    this.hostsTable.resetResourceTableSelect();

    if (this.live) {
      $(".migrate_vm_ds_selection", context).hide();
    }

    $.each(Sunstone.getDataTable(TAB_ID).elements(), function() {
      var vm_id = "" + this;

      OpenNebulaVM.show({
        data : {
          id: vm_id
        },
        timeout: true,
        success: function (request, vm_json) {
          var element = vm_json.VM;
          var hostname = OpenNebulaVM.hostnameStr(element);

          $('.confirm-resources-header', context).append(
              '' +
              Locale.tr("VM") + ' ' + element.ID + ' '+ element.NAME +' ' +
              Locale.tr("is currently running on Host") +
              ' ' + hostname + '
'
          );
        }
      });
    });
    return false;
  }

  // @param [Boolean] live Set migrate live or migrate
  function _setLive(live) {
    this.live = live;
  }
});
<|endoftext|>


<commit_before>var maze;
var mazeGenerator;

function setup(){
  createCanvas(windowWidth, windowHeight);
  maze = new Maze(width, height);
  frameRate(10);
  strokeWeight(4);

  let startingCell = maze.startingCell();
  mazeGenerator = new MazeGenerator(maze, startingCell);
}

function draw(){
  background(0);

  maze.draw();
  mazeGenerator.draw();
}

function mousePressed(){
  mazeGenerator.tick();
}

class Maze {
  constructor(_width, _height) {
    this.cellWidth = 40;
    let mazeWidth = floor(width / this.cellWidth) * this.cellWidth;
    let mazeHeight = floor(height / this.cellWidth) * this.cellWidth;
    this.mazeSize = new Rect(0, 0, mazeWidth, mazeHeight);
    this.grid = new CellGrid(this.mazeSize, this, this.cellWidth);
    this.grid.initCells();

    // this.startingCell().state = MazeCell.CELL_OPEN;
    // this.targetCell().state = MazeCell.CELL_OPEN;
  }

  startingCell(){
    return this.grid.cells[this.grid.numCols + 1];
  }

  targetCell(){
    return this.grid.cells[this.numCells - this.grid.numCols - 1];
  }

  createCell(tmpRow, tmpCol, i){
    let cell = new MazeCell(tmpRow, tmpCol, i, this);

    if (this.grid.isEdgeRowCol(tmpRow, tmpCol)) {
      // effectively make walls around the overall grid
      cell.state = MazeCell.CELL_SOLID;
      cell.bottomWall = MazeCell.WALL_SOLID;
      cell.rightWall = MazeCell.WALL_SOLID;
    }
    if (tmpRow == this.grid.numRows-2){
      cell.bottomWall = MazeCell.WALL_SOLID;
    }
    if (tmpCol == this.grid.numCols-2){
      cell.rightWall = MazeCell.WALL_SOLID;
    }
    return cell;
  }

  draw(){
    this.grid.renderViews();
  }
}

class MazeGenerator {
  constructor(maze, cell, targetCell){
    this.maze = maze;
    this.visitedCells = [];
    this.moveToCell(cell);
    this.targetCell = targetCell;
    this.state = MazeGenerator.STATE_GENERATING;
  }

  static get STATE_GENERATING(){ return 0; }
  static get STATE_STUCK(){ return -1; }

  get x(){
    return this.maze.cellWidth/2 + this.cell._col * this.maze.cellWidth;
  }
  get y(){
    return this.maze.cellWidth/2 + this.cell._row * this.maze.cellWidth;
  }

  tick(){
    if (this.cell == this.maze.targetCell()){
      console.log("Got to the end!");
      return;
    }

    this.exploreCell();
  }

  moveToCell(cell){
    this.visitedCells.push(cell);
    this.cell = cell;
    this.cell.state = MazeCell.CELL_OPEN;
  }

  exploreCell(){
    let unknownWalls = this.cell.unknownWalls;

    if (unknownWalls == undefined || unknownWalls.length == 0){
      // don't know how to handle this yet.
      console.log("stuck in dead-end");
      this.state = MazeGenerator.STATE_STUCK;
      return;
    }

    let selectedWall;
    if (unknownWalls.length == 1){
      console.log("... only one choice");
      selectedWall = unknownWalls[0];
    }else{
      let randomSelection = floor(random(unknownWalls.length));
      selectedWall = unknownWalls[randomSelection];
      console.log("selected wall: " + selectedWall);

      let nextIdx = (randomSelection+1) % unknownWalls.length;
      let wallToClose = unknownWalls[nextIdx];
      console.log("Wall to close: " + wallToClose);
      this.cell.closeWall(wallToClose);
    }

    this.cell.openWall(selectedWall);
    this.walkInDirection(selectedWall);
  }

  ensureCanWalkInDirection(){
    // before walking/opening doors, should check that next Cell is not
    // in the visitedCells (should not loop back)
    // ... if it is:
    // close the selected Wall, and choose another wall
  }

  walkInDirection(direction){
    switch(direction) {
      case 0:
        this.moveToCell(this.cell.cellAbove);
        break;
      case 1:
        this.moveToCell(this.cell.cellToRight);
        break;
      case 2:
        this.moveToCell(this.cell.cellBelow);
        break;
      case 3:
        this.moveToCell(this.cell.cellToLeft);
        break;
    }
  }

  draw(){
    fill(200, 200, 50);
    noStroke();
    let cellWidth = maze.cellWidth;
    ellipse(this.x, this.y, 0.5 * cellWidth, 0.5 * cellWidth);
  }
}

class MazeCell {
  constructor(row, col, index, maze){
    // variable names are dictated by CellGrid
    this._row = row;
    this._col = col;
    this._idx = index;

    this.maze = maze;
    this.grid = maze.grid;
    this.rightWall = MazeCell.WALL_UNKNOWN;
    this.bottomWall = MazeCell.WALL_UNKNOWN;
    this.state = MazeCell.CELL_UNKNOWN;
  }

  get cellAbove() { return this.grid.cellAbove(this._idx); }
  get cellToRight() { return this.grid.cellToRight(this._idx); }
  get cellBelow() { return this.grid.cellBelow(this._idx); }
  get cellToLeft() { return this.grid.cellToLeft(this._idx); }

  static get WALL_UNKNOWN(){ return -1; }
  static get WALL_OPEN(){ return 0; }
  static get WALL_SOLID(){ return 1; }

  static get CELL_UNKNOWN(){ return -1; }
  static get CELL_OPEN(){ return 0; }
  static get CELL_SOLID(){ return 1; }

  static get REJECTED(){ return -2; }

  get leftWall() {
    let idxToLeft = this.grid.cellIndexToLeft(this._idx);
    if (idxToLeft == undefined){
      return MazeCell.WALL_SOLID;
    }

    let cell =  this.grid.cells[idxToLeft];
    if (cell.state == MazeCell.CELL_SOLID){
      return MazeCell.WALL_SOLID;
    }else{
      return cell.rightWall;
    }
  }

  get topWall() {
    let idxToAbove = this.grid.cellIndexAbove(this._idx);
    if (idxToAbove == undefined){
      return MazeCell.WALL_SOLID;
    }

    let cell =  this.grid.cells[idxToAbove];
    if (cell.state == MazeCell.CELL_SOLID){
      return MazeCell.WALL_SOLID;
    }else{
      return cell.bottomWall;
    }
  }

  openWall(wallIdx){
    switch(wallIdx) {
      case 0:
        this.cellAbove.bottomWall = MazeCell.WALL_OPEN;
        break;
      case 1:
        this.rightWall = MazeCell.WALL_OPEN;
        break;
      case 2:
        this.bottomWall = MazeCell.WALL_OPEN;
        break;
      case 3:
        this.cellToLeft.rightWall = MazeCell.WALL_OPEN;
        break;
    }
  }

  closeWall(wallIdx){
    switch(wallIdx) {
      case 0:
        this.cellAbove.bottomWall = MazeCell.WALL_SOLID;
        break;
      case 1:
        this.rightWall = MazeCell.WALL_SOLID;
        break;
      case 2:
        this.bottomWall = MazeCell.WALL_SOLID;
        break;
      case 3:
        this.cellToLeft.rightWall = MazeCell.WALL_SOLID;
        break;
    }
  }

  get walls(){ return [this.topWall, this.rightWall, this.bottomWall, this.leftWall]; }

  get unknownWalls(){
    return this.walls.map( (wall, i) => {
        return (wall == MazeCell.WALL_UNKNOWN) ? i : MazeCell.REJECTED;
      }).filter( (idx) => {return idx != MazeCell.REJECTED; });
  }

  get openWalls(){
    return this.walls.map( (wall, i) => {
        return (wall == MazeCell.WALL_OPEN) ? i : MazeCell.REJECTED;
      }).filter( (idx) => {return idx != MazeCell.REJECTED; });
  }

  static get wall_states(){
    return [MazeCell.WALL_UNKNOWN, MazeCell.WALL_OPEN, MazeCell.WALL_SOLID];
  }

  static get cell_states(){
    return [MazeCell.CELL_UNKNOWN, MazeCell.CELL_OPEN, MazeCell.CELL_SOLID];
  }
}

// Class name is dictated by CellGrid
class CellViewer {
  renderCell(tmpCell, tmpX, tmpY, cellWidth, cellHeight){
    fill(this.colorForCellState(tmpCell.state));
    noStroke();
    rect(tmpX, tmpY, cellWidth, cellHeight);

    stroke(this.colorForWallState(tmpCell.rightWall));
    line(tmpX + cellWidth, tmpY, tmpX + cellWidth, tmpY + cellHeight);

    stroke(this.colorForWallState(tmpCell.bottomWall));
    line(tmpX, tmpY + cellHeight, tmpX + cellWidth, tmpY + cellHeight);
  }

  get colors(){
    return {
      unknown: color(80),
      unknown_line: color(120),
      open: color(100, 180, 100),
      open_line: color(120, 200, 120),
      solid: color(0)
    };
  }

  colorForWallState(wallState){
    switch (wallState) {
      case MazeCell.WALL_UNKNOWN: return this.colors.unknown_line;
      case MazeCell.WALL_OPEN:    return this.colors.open_line;
      case MazeCell.WALL_SOLID: return this.colors.solid;
    }
  }

  colorForCellState(cellState){
    switch (cellState) {
      case MazeCell.CELL_UNKNOWN: return this.colors.unknown;
      case MazeCell.CELL_OPEN:    return this.colors.open;
      case MazeCell.CELL_SOLID:   return this.colors.solid;
    }
  }
}
<commit_msg>p5js/maze-generator - Refactor moveToCell into two functions<commit_after>var maze;
var mazeGenerator;

function setup(){
  createCanvas(windowWidth, windowHeight);
  maze = new Maze(width, height);
  frameRate(10);
  strokeWeight(4);

  let startingCell = maze.startingCell();
  mazeGenerator = new MazeGenerator(maze, startingCell);
}

function draw(){
  background(0);

  maze.draw();
  mazeGenerator.draw();
}

function mousePressed(){
  mazeGenerator.tick();
}

class Maze {
  constructor(_width, _height) {
    this.cellWidth = 40;
    let mazeWidth = floor(width / this.cellWidth) * this.cellWidth;
    let mazeHeight = floor(height / this.cellWidth) * this.cellWidth;
    this.mazeSize = new Rect(0, 0, mazeWidth, mazeHeight);
    this.grid = new CellGrid(this.mazeSize, this, this.cellWidth);
    this.grid.initCells();

    // this.startingCell().state = MazeCell.CELL_OPEN;
    // this.targetCell().state = MazeCell.CELL_OPEN;
  }

  startingCell(){
    return this.grid.cells[this.grid.numCols + 1];
  }

  targetCell(){
    return this.grid.cells[this.numCells - this.grid.numCols - 1];
  }

  createCell(tmpRow, tmpCol, i){
    let cell = new MazeCell(tmpRow, tmpCol, i, this);

    if (this.grid.isEdgeRowCol(tmpRow, tmpCol)) {
      // effectively make walls around the overall grid
      cell.state = MazeCell.CELL_SOLID;
      cell.bottomWall = MazeCell.WALL_SOLID;
      cell.rightWall = MazeCell.WALL_SOLID;
    }
    if (tmpRow == this.grid.numRows-2){
      cell.bottomWall = MazeCell.WALL_SOLID;
    }
    if (tmpCol == this.grid.numCols-2){
      cell.rightWall = MazeCell.WALL_SOLID;
    }
    return cell;
  }

  draw(){
    this.grid.renderViews();
  }
}

class MazeGenerator {
  constructor(maze, cell, targetCell){
    this.maze = maze;
    this.visitedCells = [];
    this.moveToCell(cell);
    this.targetCell = targetCell;
    this.state = MazeGenerator.STATE_GENERATING;
  }

  static get STATE_GENERATING(){ return 0; }
  static get STATE_STUCK(){ return -1; }

  get x(){
    return this.maze.cellWidth/2 + this.cell._col * this.maze.cellWidth;
  }
  get y(){
    return this.maze.cellWidth/2 + this.cell._row * this.maze.cellWidth;
  }

  tick(){
    if (this.cell == this.maze.targetCell()){
      console.log("Got to the end!");
      return;
    }

    this.exploreCell();
  }

  moveToCell(cell){
    this.visitedCells.push(cell);
    this.cell = cell;
    this.cell.state = MazeCell.CELL_OPEN;
  }

  exploreCell(){
    let unknownWalls = this.cell.unknownWalls;

    if (unknownWalls == undefined || unknownWalls.length == 0){
      // don't know how to handle this yet.
      console.log("stuck in dead-end");
      this.state = MazeGenerator.STATE_STUCK;
      return;
    }

    let selectedWall;
    if (unknownWalls.length == 1){
      console.log("... only one choice");
      selectedWall = unknownWalls[0];
    }else{
      let randomSelection = floor(random(unknownWalls.length));
      selectedWall = unknownWalls[randomSelection];
      console.log("selected wall: " + selectedWall);

      let nextIdx = (randomSelection+1) % unknownWalls.length;
      let wallToClose = unknownWalls[nextIdx];
      console.log("Wall to close: " + wallToClose);
      this.cell.closeWall(wallToClose);
    }

    this.cell.openWall(selectedWall);
    this.walkInDirection(selectedWall);
  }

  ensureCanWalkInDirection(){
    // before walking/opening doors, should check that next Cell is not
    // in the visitedCells (should not loop back)
    // ... if it is:
    // close the selected Wall, and choose another wall
  }

  walkInDirection(direction){
    this.moveToCell(this.cellForDirection(direction));
  }

  cellForDirection(direction){
    switch(direction) {
      case 0:
        return this.cell.cellAbove;
      case 1:
        return this.cell.cellToRight;
      case 2:
        return this.cell.cellToRight;
      case 3:
        return this.cell.cellToLeft;
    }
  }

  draw(){
    fill(200, 200, 50);
    noStroke();
    let cellWidth = maze.cellWidth;
    ellipse(this.x, this.y, 0.5 * cellWidth, 0.5 * cellWidth);
  }
}

class MazeCell {
  constructor(row, col, index, maze){
    // variable names are dictated by CellGrid
    this._row = row;
    this._col = col;
    this._idx = index;

    this.maze = maze;
    this.grid = maze.grid;
    this.rightWall = MazeCell.WALL_UNKNOWN;
    this.bottomWall = MazeCell.WALL_UNKNOWN;
    this.state = MazeCell.CELL_UNKNOWN;
  }

  get cellAbove() { return this.grid.cellAbove(this._idx); }
  get cellToRight() { return this.grid.cellToRight(this._idx); }
  get cellBelow() { return this.grid.cellBelow(this._idx); }
  get cellToLeft() { return this.grid.cellToLeft(this._idx); }

  static get WALL_UNKNOWN(){ return -1; }
  static get WALL_OPEN(){ return 0; }
  static get WALL_SOLID(){ return 1; }

  static get CELL_UNKNOWN(){ return -1; }
  static get CELL_OPEN(){ return 0; }
  static get CELL_SOLID(){ return 1; }

  static get REJECTED(){ return -2; }

  get leftWall() {
    let idxToLeft = this.grid.cellIndexToLeft(this._idx);
    if (idxToLeft == undefined){
      return MazeCell.WALL_SOLID;
    }

    let cell =  this.grid.cells[idxToLeft];
    if (cell.state == MazeCell.CELL_SOLID){
      return MazeCell.WALL_SOLID;
    }else{
      return cell.rightWall;
    }
  }

  get topWall() {
    let idxToAbove = this.grid.cellIndexAbove(this._idx);
    if (idxToAbove == undefined){
      return MazeCell.WALL_SOLID;
    }

    let cell =  this.grid.cells[idxToAbove];
    if (cell.state == MazeCell.CELL_SOLID){
      return MazeCell.WALL_SOLID;
    }else{
      return cell.bottomWall;
    }
  }

  openWall(wallIdx){
    switch(wallIdx) {
      case 0:
        this.cellAbove.bottomWall = MazeCell.WALL_OPEN;
        break;
      case 1:
        this.rightWall = MazeCell.WALL_OPEN;
        break;
      case 2:
        this.bottomWall = MazeCell.WALL_OPEN;
        break;
      case 3:
        this.cellToLeft.rightWall = MazeCell.WALL_OPEN;
        break;
    }
  }

  closeWall(wallIdx){
    switch(wallIdx) {
      case 0:
        this.cellAbove.bottomWall = MazeCell.WALL_SOLID;
        break;
      case 1:
        this.rightWall = MazeCell.WALL_SOLID;
        break;
      case 2:
        this.bottomWall = MazeCell.WALL_SOLID;
        break;
      case 3:
        this.cellToLeft.rightWall = MazeCell.WALL_SOLID;
        break;
    }
  }

  get walls(){ return [this.topWall, this.rightWall, this.bottomWall, this.leftWall]; }

  get unknownWalls(){
    return this.walls.map( (wall, i) => {
        return (wall == MazeCell.WALL_UNKNOWN) ? i : MazeCell.REJECTED;
      }).filter( (idx) => {return idx != MazeCell.REJECTED; });
  }

  get openWalls(){
    return this.walls.map( (wall, i) => {
        return (wall == MazeCell.WALL_OPEN) ? i : MazeCell.REJECTED;
      }).filter( (idx) => {return idx != MazeCell.REJECTED; });
  }

  static get wall_states(){
    return [MazeCell.WALL_UNKNOWN, MazeCell.WALL_OPEN, MazeCell.WALL_SOLID];
  }

  static get cell_states(){
    return [MazeCell.CELL_UNKNOWN, MazeCell.CELL_OPEN, MazeCell.CELL_SOLID];
  }
}

// Class name is dictated by CellGrid
class CellViewer {
  renderCell(tmpCell, tmpX, tmpY, cellWidth, cellHeight){
    fill(this.colorForCellState(tmpCell.state));
    noStroke();
    rect(tmpX, tmpY, cellWidth, cellHeight);

    stroke(this.colorForWallState(tmpCell.rightWall));
    line(tmpX + cellWidth, tmpY, tmpX + cellWidth, tmpY + cellHeight);

    stroke(this.colorForWallState(tmpCell.bottomWall));
    line(tmpX, tmpY + cellHeight, tmpX + cellWidth, tmpY + cellHeight);
  }

  get colors(){
    return {
      unknown: color(80),
      unknown_line: color(120),
      open: color(100, 180, 100),
      open_line: color(120, 200, 120),
      solid: color(0)
    };
  }

  colorForWallState(wallState){
    switch (wallState) {
      case MazeCell.WALL_UNKNOWN: return this.colors.unknown_line;
      case MazeCell.WALL_OPEN:    return this.colors.open_line;
      case MazeCell.WALL_SOLID: return this.colors.solid;
    }
  }

  colorForCellState(cellState){
    switch (cellState) {
      case MazeCell.CELL_UNKNOWN: return this.colors.unknown;
      case MazeCell.CELL_OPEN:    return this.colors.open;
      case MazeCell.CELL_SOLID:   return this.colors.solid;
    }
  }
}
<|endoftext|>


<commit_before>var windowId = null;

chrome.windows.getCurrent(function (window) {
    windowId = window.id;
    chrome.tabs.query({windowId: window.id, active: true}, function (tabs) {
        var selectedTab = tabs[0];
        if (selectedTab && selectedTab.url.indexOf('chrome://') === -1) {
            chrome.tabs.insertCSS(selectedTab.id, {file: "jiraTimer.css"});
            chrome.tabs.executeScript(selectedTab.id, {file: "jiraTimer.js"});
        }
    });
});

chrome.windows.onFocusChanged.addListener(function (windowChangeId) {
    if (windowChangeId && windowChangeId > -1){
        windowId = windowChangeId;
        chrome.tabs.query({active: true, windowId: windowId}, function (tabs) {
            var selectedTab = tabs[0];
            bg.onTabUpdated(selectedTab.id);
        })
    }
})

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (request.method){
        bg[request.method](request);
    }
});

chrome.tabs.onActivated.addListener(function (activeInfo) {
    bg.onTabUpdated(activeInfo.tabId);
})

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
    bg.onTabUpdated(tabId);
});

// background script methods;
var bg = {
    focusOrNavigateToTab: function(req) {
        chrome.tabs.query({windowId: windowId}, function(tabs){
            tabs = $.grep(tabs, function (tab) {
                return tab.url === req.url.replace('#','');
            });
            if (tabs.length === 1){
                // if tab(s) exists with desired url, set focus to first available one
                chrome.tabs.update(tabs[0].id, {selected: true});
            } else {
                // otherwise create new tab and change focus
                chrome.tabs.create({url: req.url, active: true}, function(){});
            }
        });
    },
    onTabUpdated: function(tabId) {
        chrome.tabs.get(tabId, function (tabInfo) {
            var isJiraPage = tabInfo.url.indexOf('https://jira.') > -1 && tabInfo.url.indexOf('/browse/') > -1;
            var jiraTicketName = isJiraPage ? tabInfo.title.substr(1, tabInfo.title.indexOf(']') - 1) : 'NA';
            if (isJiraPage) {
                chrome.storage.local.get(function (res) {
                    var keys = Object.keys(res);
                    var setClass = keys.indexOf(jiraTicketName) > -1 ? 'active' : 'inactive';
                    bg.sendBackgroundMessage({method: 'updateStatusImage', setClass: setClass});
                });
            }
        });
    },
    storeTicketInfo: function(req) {
        chrome.tabs.query({windowId: windowId, active: true}, function (tabs) {
            var save = {};
            var selectedTab = tabs[0];
            if (selectedTab) {
                var jiraTicketName = selectedTab.title.substr(1, selectedTab.title.indexOf(']') - 1);

                if (req.action === 'start') {
                    save[jiraTicketName] = {start: moment.now(), tabId: selectedTab.id, url: selectedTab.url};
                    chrome.storage.local.set(save, function () {});
                } else {
                    chrome.storage.local.get(jiraTicketName, function (ticketRes) {
                        var end = (Object.values(ticketRes)[0] && Object.values(ticketRes)[0].end) ? Object.values(ticketRes)[0]['end'] : moment.now();
                        var start = Object.values(ticketRes)[0].start;
                        bg.sendBackgroundMessage({method: 'logWork', start: start, end: end, ticketName: jiraTicketName});
                    });
                }
            }
        });
    },
    sendBackgroundMessage: function(options) {
        options['from'] = 'background';
        chrome.tabs.query({active: true, windowId: windowId}, function (tabs) {
            var selectedTab = tabs[0];
            if (selectedTab) {
                chrome.tabs.sendMessage(selectedTab.id, options, function (response) {});
            }
        });
    },
    updateIcon: function(req, tabId) {
        var iconName = req.action === 'stop' ? 'inactive_19.png' : 'active_19.png';
        if (tabId) {
            chrome.browserAction.setIcon({path: iconName, tabId: tabId});
        } else {
            chrome.tabs.query({windowId: windowId, active: true}, function (tabs) {
                var selectedTab = tabs[0];
                if (selectedTab) {
                    chrome.browserAction.setIcon({path: iconName, tabId: selectedTab.id});
                }
            });
        }
    }

}

<commit_msg>replacing '#' in tabs on both sides of comparison.<commit_after>var windowId = null;

chrome.windows.getCurrent(function (window) {
    windowId = window.id;
    chrome.tabs.query({windowId: window.id, active: true}, function (tabs) {
        var selectedTab = tabs[0];
        if (selectedTab && selectedTab.url.indexOf('chrome://') === -1) {
            chrome.tabs.insertCSS(selectedTab.id, {file: "jiraTimer.css"});
            chrome.tabs.executeScript(selectedTab.id, {file: "jiraTimer.js"});
        }
    });
});

chrome.windows.onFocusChanged.addListener(function (windowChangeId) {
    if (windowChangeId && windowChangeId > -1){
        windowId = windowChangeId;
        chrome.tabs.query({active: true, windowId: windowId}, function (tabs) {
            var selectedTab = tabs[0];
            bg.onTabUpdated(selectedTab.id);
        })
    }
})

chrome.runtime.onMessage.addListener(function (request, sender, sendResponse) {
    if (request.method){
        bg[request.method](request);
    }
});

chrome.tabs.onActivated.addListener(function (activeInfo) {
    bg.onTabUpdated(activeInfo.tabId);
})

chrome.tabs.onUpdated.addListener(function (tabId, changeInfo, tab) {
    bg.onTabUpdated(tabId);
});

// background script methods;
var bg = {
    focusOrNavigateToTab: function(req) {
        chrome.tabs.query({windowId: windowId}, function(tabs){
            tabs = $.grep(tabs, function (tab) {
                return tab.url.replace('#','') === req.url.replace('#','');
            });
            if (tabs.length === 1){
                // if tab(s) exists with desired url, set focus to first available one
                chrome.tabs.update(tabs[0].id, {selected: true});
            } else {
                // otherwise create new tab and change focus
                chrome.tabs.create({url: req.url, active: true}, function(){});
            }
        });
    },
    onTabUpdated: function(tabId) {
        chrome.tabs.get(tabId, function (tabInfo) {
            var isJiraPage = tabInfo.url.indexOf('https://jira.') > -1 && tabInfo.url.indexOf('/browse/') > -1;
            var jiraTicketName = isJiraPage ? tabInfo.title.substr(1, tabInfo.title.indexOf(']') - 1) : 'NA';
            if (isJiraPage) {
                chrome.storage.local.get(function (res) {
                    var keys = Object.keys(res);
                    var setClass = keys.indexOf(jiraTicketName) > -1 ? 'active' : 'inactive';
                    bg.sendBackgroundMessage({method: 'updateStatusImage', setClass: setClass});
                });
            }
        });
    },
    storeTicketInfo: function(req) {
        chrome.tabs.query({windowId: windowId, active: true}, function (tabs) {
            var save = {};
            var selectedTab = tabs[0];
            if (selectedTab) {
                var jiraTicketName = selectedTab.title.substr(1, selectedTab.title.indexOf(']') - 1);

                if (req.action === 'start') {
                    save[jiraTicketName] = {start: moment.now(), tabId: selectedTab.id, url: selectedTab.url};
                    chrome.storage.local.set(save, function () {});
                } else {
                    chrome.storage.local.get(jiraTicketName, function (ticketRes) {
                        var end = (Object.values(ticketRes)[0] && Object.values(ticketRes)[0].end) ? Object.values(ticketRes)[0]['end'] : moment.now();
                        var start = Object.values(ticketRes)[0].start;
                        bg.sendBackgroundMessage({method: 'logWork', start: start, end: end, ticketName: jiraTicketName});
                    });
                }
            }
        });
    },
    sendBackgroundMessage: function(options) {
        options['from'] = 'background';
        chrome.tabs.query({active: true, windowId: windowId}, function (tabs) {
            var selectedTab = tabs[0];
            if (selectedTab) {
                chrome.tabs.sendMessage(selectedTab.id, options, function (response) {});
            }
        });
    },
    updateIcon: function(req, tabId) {
        var iconName = req.action === 'stop' ? 'inactive_19.png' : 'active_19.png';
        if (tabId) {
            chrome.browserAction.setIcon({path: iconName, tabId: tabId});
        } else {
            chrome.tabs.query({windowId: windowId, active: true}, function (tabs) {
                var selectedTab = tabs[0];
                if (selectedTab) {
                    chrome.browserAction.setIcon({path: iconName, tabId: selectedTab.id});
                }
            });
        }
    }

}

<|endoftext|>