<commit_before>Calc = {};
// Default State
Calc.calcing = false;
Calc.relevantObjs = {
	attackerAbility:1,
	attackerItem:1,
	defenderAbility:1,
	defenderItem:1,
	move:1
};

Calc.calcDamageNumbers = function (attacker, defender, move, field) {
	// We are in the middle of calcing
	this.calcing = true;
	// Move
	if (typeof move === 'string') move = Data.Movedex[move]; // Calc.getMove(move)
	if (!move || move.category === 'Status') return;
	// Clone attacker, defender, and move.
	this.move = Calc.moveClone(move);
	this.attacker = attacker;
	this.attackerAbility = Calc.abilityClone(attacker.ability);
	this.attackerItem = Calc.itemClone(attacker.item);
	this.defender = defender;
	this.defenderAbility = Calc.abilityClone(defender.ability);
	this.defenderItem = Calc.itemClone(defender.item);
	// this.field = Calc.getField(field);
	this.args = {}; // Keep variables from Calc.get() here

	/* listed move type -> moves that call other moves use the new move instead ->
	 * Normalize changes the move to Normal -> moves now change type (Hidden Power/Judgment/Natural Gift/Techno Blast/Weather Ball) ->
	 * if the move is Normal, Aerilate/Pixilate/Refrigerate change it to Flying/Fairy/Ice
     * -> if the move is still Normal, Ion Deluge changes to Electric -> Electrify changes the move to Electric ->
	 * Protean activates -> Gems activate if the Gem matches the move type
	*/
	this.move.type = this.get('moveType') || move.type;

	attackStatName = (move.category === 'Physical' ? 'atk' : 'spa');
	defendStatName = (move.category === 'Physical' ? 'def' : 'spd');

	attackStat = this.getStat(attackStatName, attacker.stats[attackStatName], attacker.boosts[attackStatName], true);
	defendStat = this.getStat(defendStatName, defender.stats[defendStatName], defender.boosts[defendStatName], true);

	var damage = 0;

	this.move.basePower = this.getFrom('basePower', 'move') || this.move.basePower; // Only thing that should change base power directly is the move.
	if (!this.move.basePower) return;
	var bpMod = this.getMod('bpMod') || 0x1000; // Abilities, Items, etc do it through modifiers.
	this.move.basePower = this.modify(this.move.basePower, bpMod);

	// Base Damage
	baseDamage = (Math.floor(Math.floor(Math.floor(2 * attacker.level / 5 + 2) * this.move.basePower * attackStat / defendStat) / 50) + 2);
	damage = baseDamage;

	// Spread?
	// TODO

	// Weather?
	// TODO

	// Crit?
	var critMod = this.get('critMod') || 0x1800;
	var crit = crit || false;
	if (crit) this.modify(damage, critMod);

	// Random Factor Begins To Apply Here
	// Store other variables for calculations in loop

	// STAB
	var hasSTAB = false;
	for (var i = 0; i < attacker.types.length && !hasSTAB; i++) {
		if (this.move.type === attacker.types[i]) hasSTAB = true;
	}
	var stabMod = this.get('stabMod') || 0x1800;

	// Type Effectiveness
	// var typeEff = 1;
	var typeEff = this.getTypeEff(this.move.type, defender.types);

	// Burn
	var burnEffect = false;
	if (attacker.status === 'brn') burnEffect = true;

	// Final Mods
	// TODO
	var finalMod = this.getMod('finalMod') || 0x1000;

	// Loop through damage rolls
	var damageNumbers = [];
	for (var dmgRoll = 15; damageNumbers.length < 16; dmgRoll--) {
		var rolledDamage = Math.floor(damage * (100 - dmgRoll) / 100);
		rolledDamage = this.modify(rolledDamage, (hasSTAB ? stabMod : 0x1000));
		rolledDamage = Math.floor(rolledDamage * typeEff);
		if (burnEffect) rolledDamage = Math.floor(rolledDamage/2);
		// Final Modifier
		rolledDamage = this.modify(rolledDamage, finalMod);
		if (rolledDamage < 1) rolledDamage = 1;
		damageNumbers.push(rolledDamage);
	}
	// done calcing
	this.calcing = false;
	// Clear relevantObjs
	for (var obj in this.relevantObjs) delete this[obj];
	for (var side in {attacker:1,defender:2}) delete this[side];
	delete this.args;
	return damageNumbers;
};

Calc.toModifier = function (value, numerator, denominator) {
	if (!denominator) denominator = 1;
	if (numerator && numerator.length) {
		denominator = numerator[1];
		numerator = numerator[0];
	}
	return Math.floor(numerator * 0x1000 / denominator);
};

Calc.modify = function (value, mod) {
	mod = mod || 0x1000;
	return Math.floor((value * mod + 0x800 - 1) / 0x1000);
};

Calc.chainModifiers = function (mod1, mod2) {
	mod1 = mod1 || 0x1000;
	mod2 = mod2 || 0x1000;
	return ((mod1 * mod2 + 0x800) >>> 12); // M'' = ((M * M') + 0x800) >> 12
}

Calc.compareTypes = function (oType, dType) {
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	if (!Data.TypeChart[dType]) return false;
	eff *= Data.TypeChart[dType].damageTaken[oType];
}

/* Calc.get() - returns the highest priority value or an array of values.
 * Calc.get() is a function that checks the relevant variables in a battle
 * that could affect the part of damage calculation passed to the function.
 * Uses Calc.getFrom().
*/

Calc.get = function (handle, returnArray) {
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return console.log('Blank Handle') || null;
	returnValues = [];
	var sides = {
		attack: "Attack",
		defend: "Defend"
	}
	for (obj in this.relevantObjs) {
		var value = this.getFrom(handle,obj,true);
		if (typeof value !== 'undefined') returnValues.push(value);
		if (obj.substr(0,6) in sides) {
			value = this.getFrom(handle+sides[obj.substr(0,6)], obj, true);
			if (typeof value !== 'undefined') returnValues.push(value);
		}
	}
	returnValues.sort(function(a,b){
		return b.priority - a.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};

Calc.getFrom = function (handle, fromObj, returnObj) {
	if (!this.calcing) return null;
	handle = handle || '';
	fromObj = fromObj || '';
	if (!handle || !fromObj) return null;
	var returnValues = [];
	if (!this[fromObj]) {
		console.log('Could not find this.'+fromObj);
		return;
	}
	// console.log('Running',handle,'on',fromObj);
	if (!this[fromObj]['handles'] || !this[fromObj]['handles'][handle]) return;
	var returnValue = {};
	this.self = this[fromObj];
	switch (typeof this[fromObj]['handles'][handle]) {
		case 'function':
			returnValue.value = this[fromObj]['handles'][handle].call(this);
			if (typeof returnValue.value === 'object') returnValue = $.extend(returnValue, returnValue.value);
			break;
		case 'object':
			returnValue = $.extend(returnValue, this[fromObj]['handles'][handle]);
			if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
			break;
		default: returnValue.value = this[fromObj]['handles'][handle];
	}
	if (this.self) delete this.self;
	if (typeof returnValue.value === 'undefined') return;
	returnValue.source = this[fromObj];
	if (returnObj) return returnValue;
	return returnValue.value;
};

Calc.getTypeEff = function (oType, dTypes) {
	if (!oType) return false;
	var ignoreImmunities = false;
	var immune = this.getFrom('immuneTo'+oType, 'defenderAbility');
	if (immune) return 0;
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	for (var j = 0, damageTaken; j < dTypes.length; j++) {
		if (!Data.TypeChart[dTypes[j]]) return false;
		//console.log("this.getFrom('typeEff'"+oType+", 'move'): ", this.getFrom('typeEff'+oType, 'move'))
		damageTaken = this.getFrom('typeEff'+dTypes[j], 'move') || Data.TypeChart[dTypes[j]].damageTaken[oType];
		eff *= (damageTaken !== 0 ? damageTaken : (ignoreImmunities ? 1 : 0));
	}
	return eff;
};

Calc.getMod = function (modName) { // Responsible for chaining modifiers as well
	modName = modName || '';
	modifiers = this.get(modName, true); // Get an array of modifiers
	console.log(modifiers);
	var totalMod = 0x1000;
	for (var i = 0; i < modifiers.length; i++) {
		totalMod = this.chainModifiers(totalMod, modifiers[i]);
	}
	return totalMod;
};

Calc.getStat = function (statName, stat, boost, modify) {
	if (boost) {
		if (boost > 0) stat *= ( 2 + boost ) / 2;
		if (boost < 0) stat *= 2 / (2 - boost);
		stat = Math.floor(stat);
	}
	if (modify) {
		var mod = this.getMod(statName+'Mod') || 0x1000;
		stat = this.modify(stat, mod);
	}
	return stat;
};

Calc.moveClone = function (move) {
	if (!move) return {};
	if (typeof move === 'string') move = Data.Movedex[move];
	if (typeof move !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, move);
};

Calc.itemClone = function (item) {
	if (!item) return {};
	if (typeof item === 'string') item = Data.Items[item];
	if (typeof item !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, item);
};

Calc.abilityClone = function (ability) {
	if (!ability) return {};
	if (typeof ability === 'string') ability = Data.Abilities[ability];
	if (typeof ability !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, ability);
};

/*
Calc.get = function (handle, returnArray) { // bool returnArray - if true, return array of values
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return null;
	var returnValues = [];
	for (var obj in this.relevantObjs) {
		if (!this[obj]) {
			console.log('Could not find this.'+obj);
			continue;
		}
		if (!this[obj]['handles'] || !this[obj]['handles'][handle]) continue;
		var returnValue = {};
		this.self = this[obj];
		switch (typeof this[obj]['handles'][handle]) {
			case 'function':
				returnValue.value = this[obj]['handles'][handle].call(this);
				if (typeof returnValue.value === 'object') returnValue = $.extend({}, returnValue, returnValue.value);
				break;
			case 'object':
				returnValue = $.extend(returnValue, this[obj]['handles'][handle]);
				if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
				break;
			default: returnValue.value = this[obj]['handles'][handle];
		}
		if (typeof returnValue.value === 'undefined') continue;
		returnValue.priority = returnValue.priority || 0;
		returnValue.source = this[obj];
		returnValues.push(returnValue);
		if () {

		}
	}
	if (this.self) delete this.self;
	//console.log(returnValues);
	returnValues.sort(function(a,b){
		return a.priority - b.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};*/
<commit_msg>Support returning no damage for display.<commit_after>Calc = {};
// Default State
Calc.calcing = false;
Calc.relevantObjs = {
	attackerAbility:1,
	attackerItem:1,
	defenderAbility:1,
	defenderItem:1,
	move:1
};
Calc.noDamage = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];

Calc.calcDamageNumbers = function (attacker, defender, move, field) {
	// We are in the middle of calcing
	this.calcing = true;
	// Move
	if (typeof move === 'string') move = Data.Movedex[move]; // Calc.getMove(move)
	if (!move) return;
	if (move.category === 'Status') return this.noDamage;
	// Clone attacker, defender, and move.
	this.move = Calc.moveClone(move);
	this.attacker = attacker;
	this.attackerAbility = Calc.abilityClone(attacker.ability);
	this.attackerItem = Calc.itemClone(attacker.item);
	this.defender = defender;
	this.defenderAbility = Calc.abilityClone(defender.ability);
	this.defenderItem = Calc.itemClone(defender.item);
	// this.field = Calc.getField(field);
	this.args = {}; // Keep variables from Calc.get() here

	/* listed move type -> moves that call other moves use the new move instead ->
	 * Normalize changes the move to Normal -> moves now change type (Hidden Power/Judgment/Natural Gift/Techno Blast/Weather Ball) ->
	 * if the move is Normal, Aerilate/Pixilate/Refrigerate change it to Flying/Fairy/Ice
     * -> if the move is still Normal, Ion Deluge changes to Electric -> Electrify changes the move to Electric ->
	 * Protean activates -> Gems activate if the Gem matches the move type
	*/
	this.move.type = this.get('moveType') || move.type;

	attackStatName = (move.category === 'Physical' ? 'atk' : 'spa');
	defendStatName = (move.category === 'Physical' ? 'def' : 'spd');

	attackStat = this.getStat(attackStatName, attacker.stats[attackStatName], attacker.boosts[attackStatName], true);
	defendStat = this.getStat(defendStatName, defender.stats[defendStatName], defender.boosts[defendStatName], true);

	var damage = 0;

	this.move.basePower = this.getFrom('basePower', 'move') || this.move.basePower; // Only thing that should change base power directly is the move.
	if (!this.move.basePower) return;
	var bpMod = this.getMod('bpMod') || 0x1000; // Abilities, Items, etc do it through modifiers.
	this.move.basePower = this.modify(this.move.basePower, bpMod);

	// Base Damage
	baseDamage = (Math.floor(Math.floor(Math.floor(2 * attacker.level / 5 + 2) * this.move.basePower * attackStat / defendStat) / 50) + 2);
	damage = baseDamage;

	// Spread?
	// TODO

	// Weather?
	// TODO

	// Crit?
	var critMod = this.get('critMod') || 0x1800;
	var crit = crit || false;
	if (crit) this.modify(damage, critMod);

	// Random Factor Begins To Apply Here
	// Store other variables for calculations in loop

	// STAB
	var hasSTAB = false;
	for (var i = 0; i < attacker.types.length && !hasSTAB; i++) {
		if (this.move.type === attacker.types[i]) hasSTAB = true;
	}
	var stabMod = this.get('stabMod') || 0x1800;

	// Type Effectiveness
	// var typeEff = 1;
	var typeEff = this.getTypeEff(this.move.type, defender.types);

	// Burn
	var burnEffect = false;
	if (attacker.status === 'brn') burnEffect = true;

	// Final Mods
	// TODO
	var finalMod = this.getMod('finalMod') || 0x1000;

	// Loop through damage rolls
	var damageNumbers = [];
	for (var dmgRoll = 15; damageNumbers.length < 16; dmgRoll--) {
		var rolledDamage = Math.floor(damage * (100 - dmgRoll) / 100);
		rolledDamage = this.modify(rolledDamage, (hasSTAB ? stabMod : 0x1000));
		rolledDamage = Math.floor(rolledDamage * typeEff);
		if (burnEffect) rolledDamage = Math.floor(rolledDamage/2);
		// Final Modifier
		rolledDamage = this.modify(rolledDamage, finalMod);
		if (rolledDamage < 1) rolledDamage = 1;
		damageNumbers.push(rolledDamage);
	}
	// done calcing
	this.calcing = false;
	// Clear relevantObjs
	for (var obj in this.relevantObjs) delete this[obj];
	for (var side in {attacker:1,defender:2}) delete this[side];
	delete this.args;
	return damageNumbers;
};

Calc.toModifier = function (value, numerator, denominator) {
	if (!denominator) denominator = 1;
	if (numerator && numerator.length) {
		denominator = numerator[1];
		numerator = numerator[0];
	}
	return Math.floor(numerator * 0x1000 / denominator);
};

Calc.modify = function (value, mod) {
	mod = mod || 0x1000;
	return Math.floor((value * mod + 0x800 - 1) / 0x1000);
};

Calc.chainModifiers = function (mod1, mod2) {
	mod1 = mod1 || 0x1000;
	mod2 = mod2 || 0x1000;
	return ((mod1 * mod2 + 0x800) >>> 12); // M'' = ((M * M') + 0x800) >> 12
}

Calc.compareTypes = function (oType, dType) {
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	if (!Data.TypeChart[dType]) return false;
	eff *= Data.TypeChart[dType].damageTaken[oType];
}

/* Calc.get() - returns the highest priority value or an array of values.
 * Calc.get() is a function that checks the relevant variables in a battle
 * that could affect the part of damage calculation passed to the function.
 * Uses Calc.getFrom().
*/

Calc.get = function (handle, returnArray) {
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return console.log('Blank Handle') || null;
	returnValues = [];
	var sides = {
		attack: "Attack",
		defend: "Defend"
	}
	for (obj in this.relevantObjs) {
		var value = this.getFrom(handle,obj,true);
		if (typeof value !== 'undefined') returnValues.push(value);
		if (obj.substr(0,6) in sides) {
			value = this.getFrom(handle+sides[obj.substr(0,6)], obj, true);
			if (typeof value !== 'undefined') returnValues.push(value);
		}
	}
	returnValues.sort(function(a,b){
		return b.priority - a.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};

Calc.getFrom = function (handle, fromObj, returnObj) {
	if (!this.calcing) return null;
	handle = handle || '';
	fromObj = fromObj || '';
	if (!handle || !fromObj) return null;
	var returnValues = [];
	if (!this[fromObj]) {
		console.log('Could not find this.'+fromObj);
		return;
	}
	// console.log('Running',handle,'on',fromObj);
	if (!this[fromObj]['handles'] || !this[fromObj]['handles'][handle]) return;
	var returnValue = {};
	this.self = this[fromObj];
	switch (typeof this[fromObj]['handles'][handle]) {
		case 'function':
			returnValue.value = this[fromObj]['handles'][handle].call(this);
			if (typeof returnValue.value === 'object') returnValue = $.extend(returnValue, returnValue.value);
			break;
		case 'object':
			returnValue = $.extend(returnValue, this[fromObj]['handles'][handle]);
			if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
			break;
		default: returnValue.value = this[fromObj]['handles'][handle];
	}
	if (this.self) delete this.self;
	if (typeof returnValue.value === 'undefined') return;
	returnValue.source = this[fromObj];
	if (returnObj) return returnValue;
	return returnValue.value;
};

Calc.getTypeEff = function (oType, dTypes) {
	if (!oType) return false;
	var ignoreImmunities = false;
	var immune = this.getFrom('immuneTo'+oType, 'defenderAbility');
	if (immune) return 0;
	var eff = 1;
	if (!Data.TypeChart[oType]) return false;
	for (var j = 0, damageTaken; j < dTypes.length; j++) {
		if (!Data.TypeChart[dTypes[j]]) return false;
		//console.log("this.getFrom('typeEff'"+oType+", 'move'): ", this.getFrom('typeEff'+oType, 'move'))
		damageTaken = this.getFrom('typeEff'+dTypes[j], 'move') || Data.TypeChart[dTypes[j]].damageTaken[oType];
		eff *= (damageTaken !== 0 ? damageTaken : (ignoreImmunities ? 1 : 0));
	}
	return eff;
};

Calc.getMod = function (modName) { // Responsible for chaining modifiers as well
	modName = modName || '';
	modifiers = this.get(modName, true); // Get an array of modifiers
	console.log(modifiers);
	var totalMod = 0x1000;
	for (var i = 0; i < modifiers.length; i++) {
		totalMod = this.chainModifiers(totalMod, modifiers[i]);
	}
	return totalMod;
};

Calc.getStat = function (statName, stat, boost, modify) {
	if (boost) {
		if (boost > 0) stat *= ( 2 + boost ) / 2;
		if (boost < 0) stat *= 2 / (2 - boost);
		stat = Math.floor(stat);
	}
	if (modify) {
		var mod = this.getMod(statName+'Mod') || 0x1000;
		stat = this.modify(stat, mod);
	}
	return stat;
};

Calc.moveClone = function (move) {
	if (!move) return {};
	if (typeof move === 'string') move = Data.Movedex[move];
	if (typeof move !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, move);
};

Calc.itemClone = function (item) {
	if (!item) return {};
	if (typeof item === 'string') item = Data.Items[item];
	if (typeof item !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, item);
};

Calc.abilityClone = function (ability) {
	if (!ability) return {};
	if (typeof ability === 'string') ability = Data.Abilities[ability];
	if (typeof ability !== 'object') return false;
	// Return Simple clone for now
	return $.extend(true, {}, ability);
};

/*
Calc.get = function (handle, returnArray) { // bool returnArray - if true, return array of values
	if (!this.calcing) return null;
	handle = handle || '';
	if (!handle) return null;
	var returnValues = [];
	for (var obj in this.relevantObjs) {
		if (!this[obj]) {
			console.log('Could not find this.'+obj);
			continue;
		}
		if (!this[obj]['handles'] || !this[obj]['handles'][handle]) continue;
		var returnValue = {};
		this.self = this[obj];
		switch (typeof this[obj]['handles'][handle]) {
			case 'function':
				returnValue.value = this[obj]['handles'][handle].call(this);
				if (typeof returnValue.value === 'object') returnValue = $.extend({}, returnValue, returnValue.value);
				break;
			case 'object':
				returnValue = $.extend(returnValue, this[obj]['handles'][handle]);
				if (typeof returnValue.value === 'function') returnValue.value = returnValue.value.call(this);
				break;
			default: returnValue.value = this[obj]['handles'][handle];
		}
		if (typeof returnValue.value === 'undefined') continue;
		returnValue.priority = returnValue.priority || 0;
		returnValue.source = this[obj];
		returnValues.push(returnValue);
		if () {

		}
	}
	if (this.self) delete this.self;
	//console.log(returnValues);
	returnValues.sort(function(a,b){
		return a.priority - b.priority;
	});
	if (returnArray) return returnValues.map(function(o){return o.value;});
	if (!returnValues.length) return false;
	return returnValues[0].value;
};*/
<|endoftext|>


<commit_before>"use strict";

// Third Party
const curry = require("lodash/fp/curry");
const find = require("lodash/fp/find");
const flow = require("lodash/fp/flow");
const get = require("lodash/fp/get");
const startsWith = require("lodash/fp/startsWith");

module.exports = curry((fields, name) => startsWith("customField_", name) ?
  flow(find({ id: name }), get("name"))(fields) :
  name
);
<commit_msg>Issue-5: Fix issue where customfield prefix could contain variable letters<commit_after>"use strict";

// Third Party
const curry = require("lodash/fp/curry");
const find = require("lodash/fp/find");
const flow = require("lodash/fp/flow");
const get = require("lodash/fp/get");
const startsWith = require("lodash/fp/startsWith");
const toLower = require("lodash/fp/toLower");

module.exports = curry((fields, name) => startsWith("customfield_", toLower(name)) ?
  flow(find({ id: name }), get("name"))(fields) :
  name
);
<|endoftext|>


<commit_before>sap.ui.define([
	"sap/ui/base/Object",
	"sap/m/MessageBox"
], function(UI5Object, MessageBox) {
	"use strict";

	return UI5Object.extend("com.sap.sapmentors.sitreg.events.controller.ErrorHandler", {

		/**
		 * Handles application errors by automatically attaching to the model events and displaying errors when needed.
		 * @class
		 * @param {sap.ui.core.UIComponent} oComponent reference to the app's component
		 * @public
		 * @alias com.sap.sapmentors.sitreg.events.controller.ErrorHandler
		 */
		constructor: function(oComponent) {
			this._oResourceBundle = oComponent.getModel("i18n").getResourceBundle();
			this._oComponent = oComponent;
			this._oModel = oComponent.getModel();
			this._bMessageOpen = false;
			this._sErrorText = this._oResourceBundle.getText("errorText");

			this._oModel.attachMetadataFailed(function(oEvent) {
				var oParams = oEvent.getParameters();

				this._showMetadataError(oParams.response);
			}, this);

			this._oModel.attachRequestFailed(this.onRequestFailed, this);
		},

		/* =========================================================== */
		/* event handlers                                              */
		/* =========================================================== */

		/**
		 * Event Handler for Request Fail event
		 * The user can try to refresh the metadata.
		 * @param {object} oEvent an event containing the response data
		 * @private
		 */
		onRequestFailed: function(oEvent) {
			var oParams = oEvent.getParameters();

			// An entity that was not found in the service is also throwing a 404 error in oData.
			// We already cover this case with a notFound target so we skip it here.
			// A request that cannot be sent to the server is a technical error that we have to handle though
			if ((oParams.response.statusCode !== "404") || (oParams.response.statusCode === 404 &&
					oParams.response.responseText.indexOf("Cannot POST") === 0)) {
				this._showServiceError(oParams.response);
			}
		},

		/**
		 * Shows a {@link sap.m.MessageBox} when the metadata call has failed.
		 * The user can try to refresh the metadata.
		 * @param {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showMetadataError: function(sDetails) {
			MessageBox.error(
				this._sErrorText, {
					id: "metadataErrorMessageBox",
					details: sDetails,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: [MessageBox.Action.RETRY, MessageBox.Action.CLOSE],
					onClose: function(sAction) {
						if (sAction === MessageBox.Action.RETRY) {
							this._oModel.refreshMetadata();
						}
					}.bind(this)
				}
			);
		},

		/**
		 * Shows a {@link sap.m.MessageBox}.
		 * The user can try to refresh the metadata.
		 * @param {string} sTitle the MessageBox title, {string} sMessageHeader and {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showErrorMsg: function(sTitle, sMessageHeader, sDetails) {

			MessageBox.error(
				sMessageHeader, {
					id: "ErrorMessageBox",
					title: sTitle,
					details: sDetails,
					icon: MessageBox.Icon.ERROR,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: MessageBox.Action.CLOSE

				}
			);
		},

		/**
		 * Shows a {@link sap.m.MessageBox} when a service call has failed.
		 * Only the first error message will be display.
		 * @param {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showServiceError: function(sDetails) {
			if (this._bMessageOpen) {
				return;
			}
			this._bMessageOpen = true;
			MessageBox.error(
				this._sErrorText, {
					id: "serviceErrorMessageBox",
					details: sDetails.responseText,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: [MessageBox.Action.CLOSE],
					onClose: function() {
						this._bMessageOpen = false;
					}.bind(this)
				}
			);
		}
	});

});<commit_msg>Handle com.sap.cloud.security.login header login-request<commit_after>sap.ui.define([
	"sap/ui/base/Object",
	"sap/m/MessageBox"
], function(UI5Object, MessageBox) {
	"use strict";

	return UI5Object.extend("com.sap.sapmentors.sitreg.events.controller.ErrorHandler", {

		/**
		 * Handles application errors by automatically attaching to the model events and displaying errors when needed.
		 * @class
		 * @param {sap.ui.core.UIComponent} oComponent reference to the app's component
		 * @public
		 * @alias com.sap.sapmentors.sitreg.events.controller.ErrorHandler
		 */
		constructor: function(oComponent) {
			this._oResourceBundle = oComponent.getModel("i18n").getResourceBundle();
			this._oComponent = oComponent;
			this._oModel = oComponent.getModel();
			this._bMessageOpen = false;
			this._sErrorText = this._oResourceBundle.getText("errorText");

			this._oModel.attachMetadataFailed(function(oEvent) {
				// Do we have to login?
				if (oEvent.mParameters.response.headers["com.sap.cloud.security.login"] === "login-request") {
					window.location.reload();
				}
				var oParams = oEvent.getParameters();

				this._showMetadataError(oParams.response);
			}, this);

			this._oModel.attachRequestFailed(this.onRequestFailed, this);
		},

		/* =========================================================== */
		/* event handlers                                              */
		/* =========================================================== */

		/**
		 * Event Handler for Request Fail event
		 * The user can try to refresh the metadata.
		 * @param {object} oEvent an event containing the response data
		 * @private
		 */
		onRequestFailed: function(oEvent) {
			var oParams = oEvent.getParameters();

			// An entity that was not found in the service is also throwing a 404 error in oData.
			// We already cover this case with a notFound target so we skip it here.
			// A request that cannot be sent to the server is a technical error that we have to handle though
			if ((oParams.response.statusCode !== "404") || (oParams.response.statusCode === 404 &&
					oParams.response.responseText.indexOf("Cannot POST") === 0)) {
				this._showServiceError(oParams.response);
			}
		},

		/**
		 * Shows a {@link sap.m.MessageBox} when the metadata call has failed.
		 * The user can try to refresh the metadata.
		 * @param {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showMetadataError: function(sDetails) {
			MessageBox.error(
				this._sErrorText, {
					id: "metadataErrorMessageBox",
					details: sDetails,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: [MessageBox.Action.RETRY, MessageBox.Action.CLOSE],
					onClose: function(sAction) {
						if (sAction === MessageBox.Action.RETRY) {
							this._oModel.refreshMetadata();
						}
					}.bind(this)
				}
			);
		},

		/**
		 * Shows a {@link sap.m.MessageBox}.
		 * The user can try to refresh the metadata.
		 * @param {string} sTitle the MessageBox title, {string} sMessageHeader and {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showErrorMsg: function(sTitle, sMessageHeader, sDetails) {

			MessageBox.error(
				sMessageHeader, {
					id: "ErrorMessageBox",
					title: sTitle,
					details: sDetails,
					icon: MessageBox.Icon.ERROR,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: MessageBox.Action.CLOSE

				}
			);
		},

		/**
		 * Shows a {@link sap.m.MessageBox} when a service call has failed.
		 * Only the first error message will be display.
		 * @param {string} sDetails a technical error to be displayed on request
		 * @private
		 */
		_showServiceError: function(sDetails) {
			if (this._bMessageOpen) {
				return;
			}
			this._bMessageOpen = true;
			MessageBox.error(
				this._sErrorText, {
					id: "serviceErrorMessageBox",
					details: sDetails.responseText,
					styleClass: this._oComponent.getContentDensityClass(),
					actions: [MessageBox.Action.CLOSE],
					onClose: function() {
						this._bMessageOpen = false;
					}.bind(this)
				}
			);
		}
	});

});<|endoftext|>


<commit_before><commit_msg>Fixed unix timestamp not being parsed<commit_after><|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'

import { Row, Col, Button, ButtonGroup } from 'react-bootstrap'

import { setQueryParam } from '../../actions/form'
import ModeButton from './mode-button'
import { getModeIcon, isAccessMode, hasBike, isTransit, hasTransit } from '../../util/itinerary'
import GeneralSettingsPanel from './general-settings-panel'

class SettingsSelectorPanel extends Component {
  static propTypes = {
    icons: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.state = { activePanel: 'MODES' }
  }

  // Returns whether a particular mode or TNC agency is active
  _modeIsActive (mode) {
    const {companies, queryModes} = this.props
    if (mode.mode === 'CAR_HAIL') {
      return Boolean(companies && companies.includes(mode.company.toUpperCase()))
    }

    for (const m of queryModes) {
      if (m.startsWith(mode.mode)) return true
    }
    return false
  }

  _setSoloMode (mode) {
    // save current access/transit modes
    if (hasTransit(this.props.mode)) this._lastTransitMode = this.props.mode
    this.props.setQueryParam({ mode })
  }

  _setTransit = () => {
    if (this._lastTransitMode) {
      // returning to transit from active mode
      this.props.setQueryParam({ mode: this._lastTransitMode })
      this._lastTransitMode = null
    } else {
      this.props.setQueryParam({ mode: 'WALK,TRAM,BUS,RAIL,GONDOLA' })
    }
  }

  _setWalkOnly = () => { this._setSoloMode('WALK') }

  _setBikeOnly = () => { this._setSoloMode('BICYCLE') }

  _setOwnBike = () => {
    const nonBikeModes = this.props.queryModes.filter(m => !m.startsWith('BICYCLE'))
    this.props.setQueryParam({ mode: 'BICYCLE,' + nonBikeModes.join(',') })
  }

  _setRentedBike = () => {
    const nonBikeModes = this.props.queryModes.filter(m => !m.startsWith('BICYCLE'))
    this.props.setQueryParam({ mode: 'BICYCLE_RENT,' + nonBikeModes.join(',') })
  }

  _toggleTransitMode (mode) {
    const modeStr = mode.mode || mode
    let queryModes = this.props.queryModes.slice(0) // Clone the modes array

    // do not allow the last transit mode to be deselected
    const transitModes = queryModes.filter(m => isTransit(m))
    if (transitModes.length === 1 && transitModes[0] === modeStr) return

    // If mode is currently selected, deselect it
    if (queryModes.includes(modeStr)) {
      queryModes = queryModes.filter(m => m !== modeStr)
    // Or, if mode is currently not selected, select it
    } else if (!queryModes.includes(modeStr)) {
      queryModes.push(modeStr)
    }
    this.props.setQueryParam({ mode: queryModes.join(',') })
  }

  _setAccessMode = (mode) => {
    let queryModes = this.props.queryModes.slice(0) // Clone the modes array
    const modeStr = mode.mode || mode

    // Create object to contain multiple parameter updates if needed (i.e. 'mode', 'compainies')
    const queryParamUpdate = {}

    if (this._lastTransitMode) {
      // Restore previous transit selection, if present
      queryModes = this._lastTransitMode.split(',').filter(m => !isAccessMode(m))
      this._lastTransitMode = null
    } else {
      // Otherwise, retain any currently selected transit modes
      queryModes = queryModes.filter(m => !isAccessMode(m))
    }

    // If no transit modes selected, select all
    // TODO: populate based on config
    if (!queryModes || queryModes.length === 0) queryModes = ['BUS', 'TRAM', 'RAIL', 'GONDOLA']

    // Add the access mode
    queryModes.push(modeStr)

    // Do extra stuff if mode selected was a TNC
    queryParamUpdate.companies = modeStr === 'CAR_HAIL' ? mode.company.toUpperCase() : null

    queryParamUpdate.mode = queryModes.join(',')

    this.props.setQueryParam(queryParamUpdate)
  }

  render () {
    const { mode, icons, queryModes } = this.props

    const modeHasTransit = hasTransit(mode)

    // TODO: make configurable
    const transitModes = [
      {
        mode: 'BUS',
        label: 'Bus'
      },
      {
        mode: 'TRAM',
        label: 'MAX & Streetcar'
      },
      {
        mode: 'RAIL',
        label: 'Wes'
      },
      {
        mode: 'GONDOLA',
        label: 'Aerial Tram'
      }
    ]

    const accessModes = [
      {
        mode: 'WALK',
        label: 'Walk + Transit'
      },
      {
        mode: 'BICYCLE',
        label: 'Bike + Transit'
      },
      {
        mode: 'CAR_PARK',
        label: 'Park & Ride'
      },
      {
        mode: 'CAR_HAIL',
        company: 'UBER',
        label: 'Uber + Transit'
      },
      {
        mode: 'CAR_HAIL',
        company: 'LYFT',
        label: 'Lyft + Transit'
      },
      {
        mode: 'CAR_RENT',
        label: 'car2go + Transit'
      }
    ]

    const bikeOptions = [
      {
        mode: 'BICYCLE',
        label: 'Own Bike',
        iconWidth: 18,
        action: this._setOwnBike
      },
      {
        mode: 'BICYCLE_RENT',
        label: 'Biketown',
        iconWidth: 36,
        action: this._setRentedBike
      }
    ]

    return (

          {/* Take Transit button */}
          <Row className='mode-group-row'>
            <Col xs={12}>
              <ModeButton
                enabled
                active={modeHasTransit && this._modeIsActive({ mode: 'WALK' })}
                icons={icons}
                mode={'TRANSIT'}
                height={54}
                label={'Take Transit'}
                inlineLabel
                onClick={() => this._setAccessMode('WALK')}
              />
            </Col>
          </Row>

          {/* transit access mode selector */}
          <Row className='mode-group-row'>
            {accessModes.map((mode, k) => {
              return <Col xs={4} key={k}>
                <ModeButton
                  enabled
                  active={modeHasTransit && this._modeIsActive(mode)}
                  icons={icons}
                  mode={mode}
                  height={46}
                  label={mode.label}
                  showPlusTransit
                  onClick={() => this._setAccessMode(mode)}
                />
              </Col>
            })}
          </Row>

          <Row className='mode-group-row'>
            <Col xs={2} />
            <Col xs={4}>
              <ModeButton
                enabled
                active={mode === 'WALK'}
                icons={icons}
                mode={'WALK'}
                height={36}
                label={'Walk Only'}
                inlineLabel
                onClick={this._setWalkOnly}
              />
            </Col>
            <Col xs={4}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasBike(mode)}
                icons={icons}
                mode={'BICYCLE'}
                height={36}
                label={'Bike Only'}
                inlineLabel
                onClick={this._setBikeOnly}
              />
            </Col>
            <Col xs={2} />
          </Row>

          {/* Transit mode selector */}
          <Row className='mode-group-row'>
            <Col xs={12}>

Filter Transit Modes

            </Col>
            <Col xs={12} style={{ textAlign: 'center' }}>
              {transitModes.map((mode, k) => {
                return (

                  <ModeButton
                    enabled={modeHasTransit}
                    active={this._modeIsActive(mode)}
                    icons={icons}
                    mode={mode}
                    label={mode.label}
                    showCheck
                    height={44}
                    onClick={() => this._toggleTransitMode(mode)}
                  />

)
              })}
            </Col>
          </Row>

        {/* Travel Preferences */}
        <Row>
          <Col xs={12} className='general-settings-panel'>

Travel Preferences

            {/* The bike trip type selector */}
            {hasBike(mode) && (

Use

                <ButtonGroup>
                  {bikeOptions.map((option, k) => {
                    return (
                      <Button key={k}
                        style={{ backgroundColor: queryModes.includes(option.mode) ? '#000' : '#aaa', color: '#fff', letterSpacing: 1, textTransform: 'uppercase', fontSize: 12 }}
                        onClick={option.action}
                      >

                          {getModeIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}
                </ButtonGroup>

)}

            {/* Other general settings */}
            <GeneralSettingsPanel />
          </Col>
        </Row>

    )
  }
}

// connect to redux store

const mapStateToProps = (state, ownProps) => {
  const { companies, mode, routingType } = state.otp.currentQuery
  return {
    mode,
    companies,
    modeGroups: state.otp.config.modeGroups,
    queryModes: !mode || mode.length === 0 ? [] : mode.split(','),
    routingType
  }
}

const mapDispatchToProps = { setQueryParam }

export default connect(mapStateToProps, mapDispatchToProps)(SettingsSelectorPanel)
<commit_msg>feat(form): Remove separate "Walk + transit" button from mode selector form<commit_after>import React, { Component, PropTypes } from 'react'
import { connect } from 'react-redux'

import { Row, Col, Button, ButtonGroup } from 'react-bootstrap'

import { setQueryParam } from '../../actions/form'
import ModeButton from './mode-button'
import { getModeIcon, isAccessMode, hasBike, isTransit, hasTransit } from '../../util/itinerary'
import GeneralSettingsPanel from './general-settings-panel'

class SettingsSelectorPanel extends Component {
  static propTypes = {
    icons: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.state = { activePanel: 'MODES' }
  }

  // Returns whether a particular mode or TNC agency is active
  _modeIsActive (mode) {
    const {companies, queryModes} = this.props
    if (mode.mode === 'CAR_HAIL') {
      return Boolean(companies && companies.includes(mode.company.toUpperCase()))
    }

    for (const m of queryModes) {
      if (m.startsWith(mode.mode)) return true
    }
    return false
  }

  _setSoloMode (mode) {
    // save current access/transit modes
    if (hasTransit(this.props.mode)) this._lastTransitMode = this.props.mode
    this.props.setQueryParam({ mode })
  }

  _setTransit = () => {
    if (this._lastTransitMode) {
      // returning to transit from active mode
      this.props.setQueryParam({ mode: this._lastTransitMode })
      this._lastTransitMode = null
    } else {
      this.props.setQueryParam({ mode: 'WALK,TRAM,BUS,RAIL,GONDOLA' })
    }
  }

  _setWalkOnly = () => { this._setSoloMode('WALK') }

  _setBikeOnly = () => { this._setSoloMode('BICYCLE') }

  _setOwnBike = () => {
    const nonBikeModes = this.props.queryModes.filter(m => !m.startsWith('BICYCLE'))
    this.props.setQueryParam({ mode: 'BICYCLE,' + nonBikeModes.join(',') })
  }

  _setRentedBike = () => {
    const nonBikeModes = this.props.queryModes.filter(m => !m.startsWith('BICYCLE'))
    this.props.setQueryParam({ mode: 'BICYCLE_RENT,' + nonBikeModes.join(',') })
  }

  _toggleTransitMode (mode) {
    const modeStr = mode.mode || mode
    let queryModes = this.props.queryModes.slice(0) // Clone the modes array

    // do not allow the last transit mode to be deselected
    const transitModes = queryModes.filter(m => isTransit(m))
    if (transitModes.length === 1 && transitModes[0] === modeStr) return

    // If mode is currently selected, deselect it
    if (queryModes.includes(modeStr)) {
      queryModes = queryModes.filter(m => m !== modeStr)
    // Or, if mode is currently not selected, select it
    } else if (!queryModes.includes(modeStr)) {
      queryModes.push(modeStr)
    }
    this.props.setQueryParam({ mode: queryModes.join(',') })
  }

  _setAccessMode = (mode) => {
    let queryModes = this.props.queryModes.slice(0) // Clone the modes array
    const modeStr = mode.mode || mode

    // Create object to contain multiple parameter updates if needed (i.e. 'mode', 'compainies')
    const queryParamUpdate = {}

    if (this._lastTransitMode) {
      // Restore previous transit selection, if present
      queryModes = this._lastTransitMode.split(',').filter(m => !isAccessMode(m))
      this._lastTransitMode = null
    } else {
      // Otherwise, retain any currently selected transit modes
      queryModes = queryModes.filter(m => !isAccessMode(m))
    }

    // If no transit modes selected, select all
    // TODO: populate based on config
    if (!queryModes || queryModes.length === 0) queryModes = ['BUS', 'TRAM', 'RAIL', 'GONDOLA']

    // Add the access mode
    queryModes.push(modeStr)

    // Do extra stuff if mode selected was a TNC
    queryParamUpdate.companies = modeStr === 'CAR_HAIL' ? mode.company.toUpperCase() : null

    queryParamUpdate.mode = queryModes.join(',')

    this.props.setQueryParam(queryParamUpdate)
  }

  render () {
    const { mode, icons, queryModes } = this.props

    const modeHasTransit = hasTransit(mode)

    // TODO: make configurable
    const transitModes = [
      {
        mode: 'BUS',
        label: 'Bus'
      },
      {
        mode: 'TRAM',
        label: 'MAX & Streetcar'
      },
      {
        mode: 'RAIL',
        label: 'Wes'
      },
      {
        mode: 'GONDOLA',
        label: 'Aerial Tram'
      }
    ]

    const accessModes = [
      /*{
        mode: 'WALK',
        label: 'Walk + Transit'
      },*/
      {
        mode: 'BICYCLE',
        label: 'Bike + Transit'
      },
      {
        mode: 'CAR_PARK',
        label: 'Park & Ride'
      },
      {
        mode: 'CAR_RENT',
        label: 'car2go + Transit'
      },
      {
        mode: 'CAR_HAIL',
        company: 'UBER',
        label: 'Uber + Transit'
      },
      {
        mode: 'CAR_HAIL',
        company: 'LYFT',
        label: 'Lyft + Transit'
      }
    ]

    const bikeOptions = [
      {
        mode: 'BICYCLE',
        label: 'Own Bike',
        iconWidth: 18,
        action: this._setOwnBike
      },
      {
        mode: 'BICYCLE_RENT',
        label: 'Biketown',
        iconWidth: 36,
        action: this._setRentedBike
      }
    ]

    return (

          {/* Take Transit button */}
          <Row className='mode-group-row'>
            <Col xs={12}>
              <ModeButton
                enabled
                active={modeHasTransit && this._modeIsActive({ mode: 'WALK' })}
                icons={icons}
                mode={'TRANSIT'}
                height={54}
                label={'Take Transit'}
                inlineLabel
                onClick={() => this._setAccessMode('WALK')}
              />
            </Col>
          </Row>

          {/* transit access mode selector */}
          <Row className='mode-group-row'>
            {accessModes.map((mode, k) => {
              return <Col xs={4} key={k}>
                <ModeButton
                  enabled
                  active={modeHasTransit && this._modeIsActive(mode)}
                  icons={icons}
                  mode={mode}
                  height={46}
                  label={mode.label}
                  showPlusTransit
                  onClick={() => this._setAccessMode(mode)}
                />
              </Col>
            })}
          </Row>

          <Row className='mode-group-row'>
            <Col xs={2} />
            <Col xs={4}>
              <ModeButton
                enabled
                active={mode === 'WALK'}
                icons={icons}
                mode={'WALK'}
                height={36}
                label={'Walk Only'}
                inlineLabel
                onClick={this._setWalkOnly}
              />
            </Col>
            <Col xs={4}>
              <ModeButton
                enabled
                active={!modeHasTransit && hasBike(mode)}
                icons={icons}
                mode={'BICYCLE'}
                height={36}
                label={'Bike Only'}
                inlineLabel
                onClick={this._setBikeOnly}
              />
            </Col>
            <Col xs={2} />
          </Row>

          {/* Transit mode selector */}
          <Row className='mode-group-row'>
            <Col xs={12}>

Filter Transit Modes

            </Col>
            <Col xs={12} style={{ textAlign: 'center' }}>
              {transitModes.map((mode, k) => {
                return (

                  <ModeButton
                    enabled={modeHasTransit}
                    active={this._modeIsActive(mode)}
                    icons={icons}
                    mode={mode}
                    label={mode.label}
                    showCheck
                    height={44}
                    onClick={() => this._toggleTransitMode(mode)}
                  />

)
              })}
            </Col>
          </Row>

        {/* Travel Preferences */}
        <Row>
          <Col xs={12} className='general-settings-panel'>

Travel Preferences

            {/* The bike trip type selector */}
            {hasBike(mode) && (

Use

                <ButtonGroup>
                  {bikeOptions.map((option, k) => {
                    return (
                      <Button key={k}
                        style={{ backgroundColor: queryModes.includes(option.mode) ? '#000' : '#aaa', color: '#fff', letterSpacing: 1, textTransform: 'uppercase', fontSize: 12 }}
                        onClick={option.action}
                      >

                          {getModeIcon(option.mode, icons)}

                        {option.label}
                      </Button>
                    )
                  })}
                </ButtonGroup>

)}

            {/* Other general settings */}
            <GeneralSettingsPanel />
          </Col>
        </Row>

    )
  }
}

// connect to redux store

const mapStateToProps = (state, ownProps) => {
  const { companies, mode, routingType } = state.otp.currentQuery
  return {
    mode,
    companies,
    modeGroups: state.otp.config.modeGroups,
    queryModes: !mode || mode.length === 0 ? [] : mode.split(','),
    routingType
  }
}

const mapDispatchToProps = { setQueryParam }

export default connect(mapStateToProps, mapDispatchToProps)(SettingsSelectorPanel)
<|endoftext|>


<commit_before>import React from 'react';
import { connect } from 'react-redux';
import { Map as makeMap } from 'immutable';
import includes from 'lodash/includes';

import { getCurrentTopologyOptions } from '../utils/topology-utils';
import { activeTopologyOptionsSelector } from '../selectors/topology';
import TopologyOptionAction from './topology-option-action';
import { changeTopologyOption } from '../actions/app-actions';

class TopologyOptions extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.handleOptionClick = this.handleOptionClick.bind(this);
    this.handleNoneClick = this.handleNoneClick.bind(this);
  }

  handleOptionClick(optionId, value, topologyId) {
    let nextOptions = [value];
    const { activeOptions, options } = this.props;
    const selectedOption = options.find(o => o.get('id') === optionId);

    if (selectedOption.get('selectType') === 'union') {
      // Multi-select topology options (such as k8s namespaces) are handled here.
      // Users can select one, many, or none of these options.
      // The component builds an array of the next selected values that are sent to the action.
      const opts = activeOptions.toJS();
      const selected = selectedOption.get('id');
      const isSelectedAlready = includes(opts[selected], value);

      if (isSelectedAlready) {
        // Remove the option if it is already selected
        nextOptions = opts[selected].filter(o => o !== value);
      } else {
        // Add it to the array if it's not selected
        nextOptions = opts[selected].concat(value);
      }
      // Since the user is clicking an option, remove the highlighting from the 'none' option.
      nextOptions = nextOptions.filter(o => o !== 'none');
    }
    this.props.changeTopologyOption(optionId, nextOptions, topologyId);
  }

  handleNoneClick(optionId, value, topologyId) {
    this.props.changeTopologyOption(optionId, ['none'], topologyId);
  }

  renderOption(option) {
    const { activeOptions, topologyId } = this.props;
    const optionId = option.get('id');
    const activeValue = activeOptions && activeOptions.has(optionId)
      ? activeOptions.get(optionId)
      : option.get('defaultValue');
    const noneItem = makeMap({
      value: 'none',
      label: option.get('noneLabel')
    });
    return (

          {option.get('options').map(item => (
            <TopologyOptionAction
              onClick={this.handleOptionClick}
              optionId={optionId}
              topologyId={topologyId}
              key={item.get('value')}
              activeValue={activeValue}
              item={item}
            />
          ))}
          {option.get('selectType') === 'union' &&
            <TopologyOptionAction
              onClick={this.handleNoneClick}
              optionId={optionId}
              item={noneItem}
              topologyId={topologyId}
              activeValue={activeValue}
            />
          }

    );
  }

  render() {
    const { options } = this.props;
    return (

        {options && options.toIndexedSeq().map(
          option => this.renderOption(option))}

    );
  }
}

function mapStateToProps(state) {
  return {
    options: getCurrentTopologyOptions(state),
    topologyId: state.get('currentTopologyId'),
    activeOptions: activeTopologyOptionsSelector(state)
  };
}

export default connect(
  mapStateToProps,
  { changeTopologyOption }
)(TopologyOptions);
<commit_msg>Added logic to default to noneLabel when no options are selected<commit_after>import React from 'react';
import { connect } from 'react-redux';
import { Map as makeMap } from 'immutable';
import includes from 'lodash/includes';

import { getCurrentTopologyOptions } from '../utils/topology-utils';
import { activeTopologyOptionsSelector } from '../selectors/topology';
import TopologyOptionAction from './topology-option-action';
import { changeTopologyOption } from '../actions/app-actions';

class TopologyOptions extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.handleOptionClick = this.handleOptionClick.bind(this);
    this.handleNoneClick = this.handleNoneClick.bind(this);
  }

  handleOptionClick(optionId, value, topologyId) {
    let nextOptions = [value];
    const { activeOptions, options } = this.props;
    const selectedOption = options.find(o => o.get('id') === optionId);

    if (selectedOption.get('selectType') === 'union') {
      // Multi-select topology options (such as k8s namespaces) are handled here.
      // Users can select one, many, or none of these options.
      // The component builds an array of the next selected values that are sent to the action.
      const opts = activeOptions.toJS();
      const selected = selectedOption.get('id');
      const isSelectedAlready = includes(opts[selected], value);

      if (isSelectedAlready) {
        // Remove the option if it is already selected
        nextOptions = opts[selected].filter(o => o !== value);
      } else {
        // Add it to the array if it's not selected
        nextOptions = opts[selected].concat(value);
      }
      // Since the user is clicking an option, remove the highlighting from the 'none' option,
      // unless they are removing the last option. In that case, default to the 'none' label.
      if (nextOptions.length === 0) {
        nextOptions = ['none'];
      } else {
        nextOptions = nextOptions.filter(o => o !== 'none');
      }
    }
    this.props.changeTopologyOption(optionId, nextOptions, topologyId);
  }

  handleNoneClick(optionId, value, topologyId) {
    this.props.changeTopologyOption(optionId, ['none'], topologyId);
  }

  renderOption(option) {
    const { activeOptions, topologyId } = this.props;
    const optionId = option.get('id');
    const activeValue = activeOptions && activeOptions.has(optionId)
      ? activeOptions.get(optionId)
      : option.get('defaultValue');
    const noneItem = makeMap({
      value: 'none',
      label: option.get('noneLabel')
    });
    return (

          {option.get('options').map(item => (
            <TopologyOptionAction
              onClick={this.handleOptionClick}
              optionId={optionId}
              topologyId={topologyId}
              key={item.get('value')}
              activeValue={activeValue}
              item={item}
            />
          ))}
          {option.get('selectType') === 'union' &&
            <TopologyOptionAction
              onClick={this.handleNoneClick}
              optionId={optionId}
              item={noneItem}
              topologyId={topologyId}
              activeValue={activeValue}
            />
          }

    );
  }

  render() {
    const { options } = this.props;
    return (

        {options && options.toIndexedSeq().map(
          option => this.renderOption(option))}

    );
  }
}

function mapStateToProps(state) {
  return {
    options: getCurrentTopologyOptions(state),
    topologyId: state.get('currentTopologyId'),
    activeOptions: activeTopologyOptionsSelector(state)
  };
}

export default connect(
  mapStateToProps,
  { changeTopologyOption }
)(TopologyOptions);
<|endoftext|>


<commit_before>angular.module('app.leagues.new', ['new.event.create'])
.factory('League', function($http){
  return {
    postLeague: function(league, callback) {
      $http.post('/league', league)
        .success(function(league){
          console.log('successfully posted new league');
          // get league id from league
          callback(false, league);
        })
        .error(function(err){
          console.log(err);
          callback(true, err);
        });
    },
    getLeagueId: function() {
      return league.league_id;
    }
  };

})
.controller('newLeagueController', function ($scope) { //
  $scope.step = 1;
  $scope.league = {};
  $scope.character = {};
  $scope.characters = [];

  $scope.nextStep = function(step) {
    $scope.step = step;
  };
  $scope.setLeague = function(league){
    $scope.league = league;
  };
  $scope.setCharacter = function(character){
    $scope.character = character;
  };
  $scope.appendCharacters = function(character){
    $scope.characters.push(character);
  };
  $scope.checkIfChracters = function(){
    if ($scope.characters.length) {
      $scope.nextStep(3);
    }
  };
})

.controller('createLeagueCtrl', function ($scope, League) {

  $scope.league = {};
  $scope.saveLeagueInfo = function() {

    League.postLeague($scope.league, function(err, newLeague) {
      if (newLeague) {
        $scope.nextStep(2);
        $scope.setLeague(newLeague);
      }
    });
  };
})

/*
'setCharactersCtrl' - manages characters addition, display and deletion
- currently used on leage creation step2
*/
.controller('setCharactersCtrl', function ($scope, Character) {
  //get league.id from scope
  $scope.character = {};
  $scope.addCharacter = function(){
    Character.saveCharacter($scope.league.id,function(err, character){
      if(character) {
        $scope.setCharacter(character);
        $scope.appendCharacters(character);
        $scope.character = {};
      }
    });
  };
})

.controller('scoreSettingCtrl', function ($scope) {
})
.controller('inviteFriendsCtrl', function ($scope) {
})

.factory('Character', function($http) {
  var saveCharacter = function(leagueId, callback){
    $http({
      method: 'POST',
      url: '/league/'+leagueId+'/characters',
    })
    .success(function(character){
      console.log('created a character' , character);
      callback(false, character);
    })
    .error(function(err){
      console.log(err);
      callback(true, err);
    });
  };

  return {
    saveCharacter: saveCharacter
  };
})<commit_msg>[feature] WIP invite controller added<commit_after>angular.module('app.leagues.new', ['new.event.create'])
.factory('League', function($http){
  return {
    postLeague: function(league, callback) {
      $http.post('/league', league)
        .success(function(league){
          console.log('successfully posted new league');
          // get league id from league
          callback(false, league);
        })
        .error(function(err){
          console.log(err);
          callback(true, err);
        });
    },
    getLeagueId: function() {
      return league.league_id;
    }
  };

})
.controller('newLeagueController', function ($scope) { //
  $scope.step = 1;
  $scope.league = {};
  $scope.character = {};
  $scope.characters = [];

  $scope.nextStep = function(step) {
    $scope.step = step;
  };
  $scope.setLeague = function(league){
    $scope.league = league;
  };
  $scope.setCharacter = function(character){
    $scope.character = character;
  };
  $scope.appendCharacters = function(character){
    $scope.characters.push(character);
  };
  $scope.checkIfChracters = function(){
    if ($scope.characters.length) {
      $scope.nextStep(3);
    }
  };
})

.controller('createLeagueCtrl', function ($scope, League) {

  $scope.league = {};
  $scope.saveLeagueInfo = function() {

    League.postLeague($scope.league, function(err, newLeague) {
      if (newLeague) {
        $scope.nextStep(2);
        $scope.setLeague(newLeague);
      }
    });
  };
})

/*
'setCharactersCtrl' - manages characters addition, display and deletion
- currently used on leage creation step2
*/
.controller('setCharactersCtrl', function ($scope, Character) {
  //get league.id from scope
  $scope.character = {};
  $scope.addCharacter = function(){
    Character.saveCharacter($scope.league.id,function(err, character){
      if(character) {
        $scope.setCharacter(character);
        $scope.appendCharacters(character);
        $scope.character = {};
      }
    });
  };
})

.controller('scoreSettingCtrl', function ($scope) {
})

.controller('inviteCtrl', function ($scope) {

.factory('Character', function($http) {
  var saveCharacter = function(leagueId, callback){
    $http({
      method: 'POST',
      url: '/league/'+leagueId+'/characters',
    })
    .success(function(character){
      console.log('created a character' , character);
      callback(false, character);
    })
    .error(function(err){
      console.log(err);
      callback(true, err);
    });
  };

  return {
    saveCharacter: saveCharacter
  };
})<|endoftext|>


<commit_before>/**
 * @file MaterialTextField component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Theme from '../Theme';

import TextField from '../TextField';
import MaterialFieldSeparator from '../_MaterialFieldSeparator';

import Util from '../_vendors/Util';

export default class MaterialTextField extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: '',
            isFocus: false,
            isHover: false
        };

        this.triggerFocusHandler = ::this.triggerFocusHandler;
        this.triggerBlurHandler = ::this.triggerBlurHandler;
        this.triggerChangeHandler = ::this.triggerChangeHandler;
        this.triggerMouseOverHandler = ::this.triggerMouseOverHandler;
        this.triggerMouseOutHandler = ::this.triggerMouseOutHandler;

    }

    triggerFocusHandler(...args) {
        this.setState({
            isFocus: true
        }, () => {
            const {onFocus} = this.props;
            onFocus && onFocus(...args);
        });
    }

    triggerBlurHandler(...args) {
        this.setState({
            isFocus: false
        }, () => {
            const {onBlur} = this.props;
            onBlur && onBlur(...args);
        });
    }

    triggerChangeHandler(value) {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    }

    triggerMouseOverHandler(...args) {
        this.setState({
            isHover: true
        }, () => {
            const {onMouseOver} = this.props;
            onMouseOver && onMouseOver(...args);
        });
    }

    triggerMouseOutHandler(...args) {
        this.setState({
            isHover: false
        }, () => {
            const {onMouseOut} = this.props;
            onMouseOut && onMouseOut(...args);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        this.setState({
            value: this.props.value
        });
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate,
                ...restProps
            } = this.props,
            {isFocus, isHover, value} = this.state,

            wrapperClassName = (isLabelAnimate ? ' animated' : '') + (label ? ' has-label' : '')
                + (isFocus ? ' focused' : '') + (value ? ' has-value' : '') + (className ? ' ' + className : '');

        return (

                {
                    label ?

                            {label}

                        :
                        null
                }

                <TextField {...restProps}
                           theme={theme}
                           value={value}
                           onFocus={this.triggerFocusHandler}
                           onBlur={this.triggerBlurHandler}
                           onMouseOver={this.triggerMouseOverHandler}
                           onMouseOut={this.triggerMouseOutHandler}
                           onChange={this.triggerChangeHandler}/>

                <MaterialFieldSeparator theme={theme}
                                        isHover={isHover}
                                        isFocus={isFocus}/>

        );

    }
};

MaterialTextField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * Specifies the type of input to display such as "password" or "text".
     */
    type: PropTypes.oneOf(Util.enumerateValue(TextField.Type)),

    /**
     * The name of the text field.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.string,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The placeholder of the text field.
     */
    placeholder: PropTypes.string,

    /**
     * The value of the text field.Type can be string or number.
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

    /**
     * Use this property to display an icon.
     */
    iconCls: PropTypes.string,

    /**
     * Disables the textField if set to true.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the textField will can't editable.
     */
    readOnly: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The message of the textField.
     */
    infoMsg: PropTypes.string,

    /**
     * If true,clearButton will display when the textField is not empty.
     */
    clearButtonVisible: PropTypes.bool,

    /**
     * Use this property to display an icon.
     */
    rightIconCls: PropTypes.string,

    /**
     * If true,passwordButton will display.
     */
    passwordButtonVisible: PropTypes.bool,

    // valid
    /**
     * If true,the textField must be required.
     */
    required: PropTypes.bool,

    /**
     * The maximum length of textField to enter.
     */
    maxLength: PropTypes.number,

    /**
     * Maximum number of textField that can be entered.
     */
    max: PropTypes.number,

    /**
     * Minimum number of textField that can be entered.
     */
    min: PropTypes.number,

    /**
     * The matching rule of textField.
     */
    pattern: PropTypes.object,

    /**
     * The invalid message of textField.
     */
    patternInvalidMsg: PropTypes.string,

    /**
     *
     */
    autoComplete: PropTypes.string,

    /**
     *
     */
    autoCorrect: PropTypes.string,

    /**
     *
     */
    autoCapitalize: PropTypes.string,

    /**
     *
     */
    spellCheck: PropTypes.string,

    /**
     * Callback function fired when the textField is changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when the press enter.
     */
    onPressEnter: PropTypes.func,

    /**
     * Callback function fired when textField valid.
     */
    onValid: PropTypes.func,

    /**
     * Callback function fired when textField invalid.
     */
    onInvalid: PropTypes.func,

    /**
     * Callback function fired when textField focus.
     */
    onFocus: PropTypes.func,

    /**
     * Callback function fired when textField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when textField clear.
     */
    onClear: PropTypes.func,

    /**
     * Callback function fired when password visible.
     */
    onPasswordVisible: PropTypes.func,

    /**
     * Callback function fired when password invisible.
     */
    onPasswordInvisible: PropTypes.func,

    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTextField.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    type: 'text',
    name: '',
    label: '',
    isLabelAnimate: true,
    placeholder: '',
    value: '',
    iconCls: '',
    disabled: false,
    readOnly: false,
    autoFocus: false,
    infoMsg: '',

    clearButtonVisible: true,
    passwordButtonVisible: true,

    // valid
    required: false,
    patternInvalidMsg: '',
    preventInvalidInput: false,

    autoComplete: 'off',
    autoCorrect: 'off',
    autoCapitalize: 'off',
    spellCheck: 'false',

    fieldMsgVisible: true

};<commit_msg>update MaterialTextField<commit_after>/**
 * @file MaterialTextField component
 * @author liangxiaojun(liangxiaojun@derbysoft.com)
 */

import React, {Component} from 'react';
import PropTypes from 'prop-types';
import Theme from '../Theme';

import TextField from '../TextField';
import MaterialFieldSeparator from '../_MaterialFieldSeparator';

import Util from '../_vendors/Util';

export default class MaterialTextField extends Component {

    constructor(props, ...restArgs) {

        super(props, ...restArgs);

        this.state = {
            value: '',
            isFocus: false,
            isHover: false
        };

        this.triggerFocusHandler = ::this.triggerFocusHandler;
        this.triggerBlurHandler = ::this.triggerBlurHandler;
        this.triggerChangeHandler = ::this.triggerChangeHandler;
        this.triggerMouseOverHandler = ::this.triggerMouseOverHandler;
        this.triggerMouseOutHandler = ::this.triggerMouseOutHandler;

    }

    triggerFocusHandler(...args) {
        this.setState({
            isFocus: true
        }, () => {
            const {onFocus} = this.props;
            onFocus && onFocus(...args);
        });
    }

    triggerBlurHandler(...args) {
        this.setState({
            isFocus: false
        }, () => {
            const {onBlur} = this.props;
            onBlur && onBlur(...args);
        });
    }

    triggerChangeHandler(value) {
        this.setState({
            value
        }, () => {
            const {onChange} = this.props;
            onChange && onChange(value);
        });
    }

    triggerMouseOverHandler(...args) {
        this.setState({
            isHover: true
        }, () => {
            const {onMouseOver} = this.props;
            onMouseOver && onMouseOver(...args);
        });
    }

    triggerMouseOutHandler(...args) {
        this.setState({
            isHover: false
        }, () => {
            const {onMouseOut} = this.props;
            onMouseOut && onMouseOut(...args);
        });
    }

    componentWillReceiveProps(nextProps) {
        if (nextProps.value !== this.state.value) {
            this.setState({
                value: nextProps.value
            });
        }
    }

    componentDidMount() {
        this.setState({
            value: this.props.value
        });
    }

    render() {

        const {
                className, style, theme, label, isLabelAnimate,
                ...restProps
            } = this.props,
            {isFocus, isHover, value} = this.state,

            wrapperClassName = (isLabelAnimate ? ' animated' : '') + (label ? ' has-label' : '')
                + (isFocus ? ' focused' : '') + (value ? ' has-value' : '') + (className ? ' ' + className : '');

        return (

                {
                    label ?

                            {label}

                        :
                        null
                }

                <TextField {...restProps}
                           theme={theme}
                           value={value}
                           onFocus={this.triggerFocusHandler}
                           onBlur={this.triggerBlurHandler}
                           onMouseOver={this.triggerMouseOverHandler}
                           onMouseOut={this.triggerMouseOutHandler}
                           onChange={this.triggerChangeHandler}/>

                <MaterialFieldSeparator theme={theme}
                                        isHover={isHover}
                                        isFocus={isFocus}/>

        );

    }
};

MaterialTextField.propTypes = {

    /**
     * The CSS class name of the root element.
     */
    className: PropTypes.string,

    /**
     * Override the styles of the root element.
     */
    style: PropTypes.object,

    /**
     * The TextField theme.
     */
    theme: PropTypes.oneOf(Util.enumerateValue(Theme)),

    /**
     * Specifies the type of input to display such as "password" or "text".
     */
    type: PropTypes.oneOf(Util.enumerateValue(TextField.Type)),

    /**
     * The name of the text field.
     */
    name: PropTypes.string,

    /**
     * The label of the text field.
     */
    label: PropTypes.string,

    /**
     * The animate of the text field.
     */
    isLabelAnimate: PropTypes.bool,

    /**
     * The placeholder of the text field.
     */
    placeholder: PropTypes.string,

    /**
     * The value of the text field.Type can be string or number.
     */
    value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),

    /**
     * Use this property to display an icon.
     */
    iconCls: PropTypes.string,

    /**
     * Disables the textField if set to true.
     */
    disabled: PropTypes.bool,

    /**
     * If true,the textField will can't editable.
     */
    readOnly: PropTypes.bool,

    /**
     * If true,the textField will autoFocus.
     */
    autoFocus: PropTypes.bool,

    /**
     * The message of the textField.
     */
    infoMsg: PropTypes.string,

    /**
     * If true,clearButton will display when the textField is not empty.
     */
    clearButtonVisible: PropTypes.bool,

    /**
     * Use this property to display an icon.
     */
    rightIconCls: PropTypes.string,

    /**
     * If true,passwordButton will display.
     */
    passwordButtonVisible: PropTypes.bool,

    // valid
    /**
     * If true,the textField must be required.
     */
    required: PropTypes.bool,

    /**
     * The maximum length of textField to enter.
     */
    maxLength: PropTypes.number,

    /**
     * Maximum number of textField that can be entered.
     */
    max: PropTypes.number,

    /**
     * Minimum number of textField that can be entered.
     */
    min: PropTypes.number,

    /**
     * The matching rule of textField.
     */
    pattern: PropTypes.object,

    /**
     * The invalid message of textField.
     */
    patternInvalidMsg: PropTypes.string,

    /**
     *
     */
    autoComplete: PropTypes.string,

    /**
     *
     */
    autoCorrect: PropTypes.string,

    /**
     *
     */
    autoCapitalize: PropTypes.string,

    /**
     *
     */
    spellCheck: PropTypes.string,

    /**
     * Callback function fired when the textField is changed.
     */
    onChange: PropTypes.func,

    /**
     * Callback function fired when the press enter.
     */
    onPressEnter: PropTypes.func,

    /**
     * Callback function fired when textField valid.
     */
    onValid: PropTypes.func,

    /**
     * Callback function fired when textField invalid.
     */
    onInvalid: PropTypes.func,

    /**
     * Callback function fired when textField focus.
     */
    onFocus: PropTypes.func,

    /**
     * Callback function fired when textField blur.
     */
    onBlur: PropTypes.func,

    /**
     * Callback function fired when textField clear.
     */
    onClear: PropTypes.func,

    /**
     * Callback function fired when password visible.
     */
    onPasswordVisible: PropTypes.func,

    /**
     * Callback function fired when password invisible.
     */
    onPasswordInvisible: PropTypes.func,

    onMouseOver: PropTypes.func,
    onMouseOut: PropTypes.func

};

MaterialTextField.defaultProps = {

    className: '',
    style: null,
    theme: Theme.DEFAULT,

    type: 'text',
    name: '',
    label: '',
    isLabelAnimate: true,
    placeholder: '',
    value: '',
    iconCls: '',
    disabled: false,
    readOnly: false,
    autoFocus: false,
    infoMsg: '',

    clearButtonVisible: true,
    passwordButtonVisible: true,

    // valid
    required: false,
    patternInvalidMsg: '',
    preventInvalidInput: false,

    autoComplete: 'off',
    autoCorrect: 'off',
    autoCapitalize: 'off',
    spellCheck: 'false',

    fieldMsgVisible: true

};<|endoftext|>


<commit_before>// A robot is located at the top-left corner of a m x n grid.

// The robot can only move either down or right at any point in time.
// The robot is trying to reach the bottom-right corner of the grid.

// How many possible unique paths are there?

// Note: m and n will be at most 100.

// Input: Integer, Integer
// ex. 2, 3
// ex. 3, 3

// Output: Integer
// ex. 3
// ex. 6

var uniquePaths = function(m, n) {
    var map = [];
    for(var i = 0; i < m; i++) {
        map[i] = [];
        for (var j = 0; j < n; j++) {
            map[i][j] = 0;
        }
    }
    for(i = 0; i<m; i++){
        map[i][0] = 1;
    }
    for(j= 0; j<n; j++){
        map[0][j] = 1;
    }
    for(i = 1; i<m; i++){
        for(j = 1; j<n; j++){
            map[i][j] = map[i-1][j]+map[i][j-1];
        }
    }
    return map[m-1][n-1];
};
<commit_msg>add notes<commit_after>// A robot is located at the top-left corner of a m x n grid.

// The robot can only move either down or right at any point in time.
// The robot is trying to reach the bottom-right corner of the grid.

// How many possible unique paths are there?

// Note: m and n will be at most 100.

// Input: Integer, Integer
// ex. 2, 3
// ex. 3, 3

// Output: Integer
// ex. 3
// ex. 6

var uniquePaths = function(m, n) {
    var map = [];
    for(var i = 0; i < m; i++) {
        map[i] = [];
        for (var j = 0; j < n; j++) {
            map[i][j] = 0;
        }
    }
    for(i = 0; i<m; i++){ // When (n===0||m===0) the function always returns 1 since the robot can't go left or up.
        map[i][0] = 1;
    }
    for(j= 0; j<n; j++){ // Populate the edges with 1 first and use DP to get the full 2-D array.
        map[0][j] = 1;
    }
    for(i = 1; i<m; i++){
        for(j = 1; j<n; j++){
            map[i][j] = map[i-1][j]+map[i][j-1]; // For all other cells. The result = uniquePaths(m-1,n)+uniquePaths(m,n-1)
        }
    }
    return map[m-1][n-1];
};
<|endoftext|>